package com.inspur.security.cbb3.kms.utils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPrivateKey;
import java.security.spec.DSAPrivateKeySpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.EncryptedPrivateKeyInfo;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jcajce.spec.SM2ParameterSpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.openssl.PEMDecryptorProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMEncryptor;
import org.bouncycastle.openssl.PEMException;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
import org.bouncycastle.openssl.jcajce.JcePEMEncryptorBuilder;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.bouncycastle.util.io.pem.PemWriter;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Strings;
import com.inspur.security.cbb3.kms.enums.AsymmetricCommonPrivateKeyFormatType;
import com.inspur.security.cbb3.kms.enums.AsymmetricPublicKeyFormatType;
import com.inspur.security.cbb3.kms.enums.AsymmetricSM2PrivateKeyFormatType;
import com.inspur.security.cbb3.kms.utils.asn1.DSAPrivateKeyPKCS1;
import com.inspur.security.cbb3.kms.utils.parameter.cipher.CipherParams;
import com.inspur.security.cbb3.kms.utils.parameter.cipher.impl.AESCipherParams;
import com.inspur.security.cbb3.kms.utils.parameter.cipher.impl.DES3CipherParams;
import com.inspur.security.cbb3.kms.utils.parameter.cipher.impl.RSACipherParams;
import com.inspur.security.cbb3.kms.utils.parameter.cipher.impl.SM2CipherParams;
import com.inspur.security.cbb3.kms.utils.parameter.cipher.impl.SM4CipherParams;
import com.inspur.security.cbb3.kms.utils.parameter.keygen.KeyGenParams;
import com.inspur.security.cbb3.kms.utils.parameter.keygen.impl.AESKeyGenParams;
import com.inspur.security.cbb3.kms.utils.parameter.keygen.impl.DES3KeyGenParams;
import com.inspur.security.cbb3.kms.utils.parameter.keygen.impl.DSAKeyGenParams;
import com.inspur.security.cbb3.kms.utils.parameter.keygen.impl.RSAKeyGenParams;
import com.inspur.security.cbb3.kms.utils.parameter.keygen.impl.SM2KeyGenParams;
import com.inspur.security.cbb3.kms.utils.parameter.keygen.impl.SM4KeyGenParams;
import com.inspur.security.cbb3.kms.utils.parameter.messagedigest.MessageDigestParams;
import com.inspur.security.cbb3.kms.utils.parameter.messagedigest.impl.MessageDigestParamsImpl;
import com.inspur.security.cbb3.kms.utils.parameter.signature.SignatureParams;
import com.inspur.security.cbb3.kms.utils.parameter.signature.impl.DSASignatureParams;
import com.inspur.security.cbb3.kms.utils.parameter.signature.impl.RSASignatureParams;
import com.inspur.security.cbb3.kms.utils.parameter.signature.impl.SM2SignatureParams;

import lombok.extern.slf4j.Slf4j;

/**
 * 密钥工具类，包含密钥生成、加解密、签名验签等功能
 *
 * @author kangxuezhong
 */
@Slf4j
public class KeyUtil {
	static final Provider PROVIDER = new BouncyCastleProvider();

	public static final String TYPE_PREFIX_PKCS8_PRIVATE_KEY = "PRIVATE KEY";// PKCS#8前缀
	public static final String TYPE_PREFIX_X509_PUBLIC_KEY = "PUBLIC KEY";// X509前缀
	public static final String TYPE_PREFIX_RSA_PKCS1_PRIVATE_KEY = "RSA PRIVATE KEY";// RSA私钥前缀
	public static final String TYPE_PREFIX_RSA_PKCS1_PUBLIC_KEY = "RSA PUBLIC KEY";// RSA公钥前缀
	public static final String TYPE_PREFIX_DSA_PKCS1_PRIVATE_KEY = "DSA PRIVATE KEY";// DSA私钥前缀
	public static final String TYPE_PREFIX_SM2_GMT_PRIVATE_KEY = "EC PRIVATE KEY";// EC私钥前缀
	public static final String TYPE_PREFIX_PKCS8_ENCRYPTED_PRIVATE_KEY = "ENCRYPTED PRIVATE KEY";// 口令加密私钥的前缀

	public static final String TYPE_ALGORITHM_RSA = "RSA";
	public static final String TYPE_ALGORITHM_DSA = "DSA";
	public static final String TYPE_ALGORITHM_EC = "EC";// EC即为ECC椭圆曲线算法；
	public static final String TYPE_ALGORITHM_ECDSA = "ECDSA";// ECDSA是ECC与DSA的结合，整个签名过程与DSA类似，不一样的是签名中采取的算法为ECC。有时候SM2（EC）密钥会识别为ECDSA
	public static final String TYPE_ALGORITHM_SM2 = "SM2";// SM2基于ECC椭圆曲线算法，SM2是一个曲线参数的名称，其它的还有prime256v1、secp128r2等参数；
	public static final String TYPE_ALGORITHM_AES = "AES";
	public static final String TYPE_ALGORITHM_3DES = "DESede";// 3DES算法，Java中以DESede为标志
	public static final String TYPE_ALGORITHM_SM4 = "SM4";
	public static final String TYPE_ALGORITHM_SM3 = "SM3";

	public static final String TYPE_MODE_CBC = "CBC";

	public static final Set<String> ALGORITHM_SecretKeyFactory = new LinkedHashSet<>();// 对称密钥工程支持的算法集
	public static final Set<String> ALGORITHM_KeyFactory = new LinkedHashSet<>();// 非对称密钥工厂支持的算法集
	public static final Set<String> ALGORITHM_KeyGenerator = new LinkedHashSet<>();// 对称密钥生成器支持的算法集
	public static final Set<String> ALGORITHM_KeyPairGenerator = new LinkedHashSet<>();// 非对称密钥生成器支持的算法集
	public static final Set<String> ALGORITHM_Cipher = new LinkedHashSet<>();// 加解密支持的算法集
	public static final Set<String> ALGORITHM_MessageDigest = new LinkedHashSet<>();// 信息摘要支持的算法集
	public static final Set<String> ALGORITHM_Signature = new LinkedHashSet<>();// 签名验签支持的算法集

	static {
		// 为JCA/JCE引入BCProvider
		Security.addProvider(PROVIDER);
	}

	/**
	 * 统计密钥生成、加密、签名支持的算法。 KMS本身只支持AES、3DES、SM4、RSA、DSA、SM2六种算法，这里将所有支持的算法列出，方便以后扩充。
	 */
	static {
		Provider[] providers = Security.getProviders();
		if (null != providers) {
			for (Provider provider : providers) {
				Set<Provider.Service> services = provider.getServices();
				for (Provider.Service service : services) {
					switch (service.getType()) {
					case "SecretKeyFactory":
						ALGORITHM_SecretKeyFactory.add(service.getAlgorithm());
						break;
					case "KeyFactory":
						ALGORITHM_KeyFactory.add(service.getAlgorithm());
						break;
					case "KeyGenerator":
						ALGORITHM_KeyGenerator.add(service.getAlgorithm());
						break;
					case "KeyPairGenerator":
						ALGORITHM_KeyPairGenerator.add(service.getAlgorithm());
						break;
					case "Cipher":
						ALGORITHM_Cipher.add(service.getAlgorithm());
						break;
					case "MessageDigest":
						ALGORITHM_MessageDigest.add(service.getAlgorithm());
						break;
					case "Signature":
						ALGORITHM_Signature.add(service.getAlgorithm());
						break;
					default:
						break;
					}
				}
			}
		}
	}

	/**
	 * DER转PEM
	 *
	 * @param typePrefix 密钥类型前缀，如"PRIVATE KEY". 参考类型：
	 *                   {@link #TYPE_PREFIX_PKCS8_PRIVATE_KEY},
	 *                   {@link #TYPE_PREFIX_X509_PUBLIC_KEY},
	 *                   {@link #TYPE_PREFIX_RSA_PKCS1_PRIVATE_KEY},
	 *                   {@link #TYPE_PREFIX_RSA_PKCS1_PUBLIC_KEY},
	 *                   {@link #TYPE_PREFIX_DSA_PKCS1_PRIVATE_KEY},
	 *                   {@link #TYPE_PREFIX_SM2_GMT_PRIVATE_KEY}
	 * @param der        编码后的密钥数据
	 * @return PKCS8编码的PEM格式字符串
	 * @throws IOException IO写入异常
	 */
	private static String derToPem(String typePrefix, byte[] der) throws IOException {
		PemObject pemObject = new PemObject(typePrefix, der);
		StringWriter stringWriter = new StringWriter();
		try (PemWriter pemWriter = new PemWriter(stringWriter)) {
			pemWriter.writeObject(pemObject);
		} catch (IOException e) {
			log.error("derToPem error", e);
			throw e;
		}
		return stringWriter.toString();
	}

	/**
	 * PEM转DER
	 *
	 * @param pemKey PEM格式字符串
	 * @return DER字节数组
	 */
	private static byte[] pemToDer(String pemKey) throws IOException {
		InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(pemKey.getBytes()));
		byte[] der;
		try (PemReader pemReader = new PemReader(isr)) {
			der = pemReader.readPemObject().getContent();
		} catch (IOException e) {
			log.error("pemToDer error", e);
			throw e;
		}
		return der;
	}

	/**
	 * PEM转简单字符串
	 *
	 * @param pem PEM格式字符串
	 * @return 简单字符串，不包含“BEGIN、“END”开头结尾，以及“\r”、“\n”回车换行符。
	 * @throws IOException IO异常
	 */
	private static String pemToStr(String pem) throws IOException {
		byte[] der = pemToDer(pem);
		return Base64.getEncoder().encodeToString(der);
	}

	/**
	 * 简单字符串转PEM
	 *
	 * @param typePrefix 密钥类型前缀，如"PRIVATE KEY". 参考类型：
	 *                   {@link #TYPE_PREFIX_PKCS8_PRIVATE_KEY},
	 *                   {@link #TYPE_PREFIX_X509_PUBLIC_KEY},
	 *                   {@link #TYPE_PREFIX_RSA_PKCS1_PRIVATE_KEY},
	 *                   {@link #TYPE_PREFIX_RSA_PKCS1_PUBLIC_KEY},
	 *                   {@link #TYPE_PREFIX_DSA_PKCS1_PRIVATE_KEY},
	 *                   {@link #TYPE_PREFIX_SM2_GMT_PRIVATE_KEY}
	 * @param str        简单字符串，不包含“BEGIN、“END”开头结尾，以及“\r”、“\n”回车换行符。
	 * @return PEM格式字符串
	 * @throws IOException IO异常
	 */
	private static String strToPem(String typePrefix, String str) throws IOException {
		byte[] der = Base64.getDecoder().decode(str);
		return derToPem(typePrefix, der);
	}

	/**
	 * DER转简单字符串
	 *
	 * @param der DER编码的密钥
	 * @return Base64编码的简单字符串
	 */
	private static String derToStr(byte[] der) {
		return Base64.getEncoder().encodeToString(der);
	}

	/**
	 * 简单字符串转DER
	 *
	 * @param str Base64编码的简单字符串
	 * @return DER编码的密钥
	 */
	private static byte[] strToDer(String str) {
		return Base64.getDecoder().decode(str);
	}

	/**
	 * Base64编码的字符串转Hex编码的字符串
	 *
	 * @param b64Str Base64编码的字符串
	 * @return Hex编码的字符串
	 */
	private static String base64ToHex(String b64Str) {
		return Hex.toHexString(Base64.getDecoder().decode(b64Str));
	}

	/**
	 * Hex编码的字符串转Base64编码的字符串
	 *
	 * @param hexStr Base64编码的字符串
	 * @return Hex编码的字符串
	 */
	private static String hexToBase64(String hexStr) {
		return Base64.getEncoder().encodeToString(Hex.decode(hexStr));
	}

	/**
	 * 加载Java通用X509标准的公钥
	 *
	 * @param pubKeyX509Der 公钥
	 * @param algorithm     算法
	 * @return Java通用公钥接口
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 * @throws InvalidKeySpecException  无效的密钥规范异常
	 */
	private static PublicKey loadX509Publickey(byte[] pubKeyX509Der, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException {
		if (isSM2Algorithm(algorithm)) {
			algorithm = TYPE_ALGORITHM_EC;
		}
		KeyFactory keyFactory;
		try {
			keyFactory = KeyFactory.getInstance(algorithm);
		} catch (NoSuchAlgorithmException e) {
			log.error("loadX509Publickey error", e);
			throw e;
		}
		try {
			return keyFactory.generatePublic(new X509EncodedKeySpec(pubKeyX509Der));
		} catch (InvalidKeySpecException e) {
			log.error("loadX509Publickey error", e);
			throw e;
		}
	}

	/**
	 * 加载Java通用PKCS#8标准的私钥
	 *
	 * @param priKeyPKCS8Der 私钥
	 * @param algorithm      算法
	 * @return Java通用私钥接口
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 * @throws InvalidKeySpecException  无效的密钥规范异常
	 */
	private static PrivateKey loadPKCS8Privatekey(byte[] priKeyPKCS8Der, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException {
		if (isSM2Algorithm(algorithm)) {
			algorithm = TYPE_ALGORITHM_EC;
		}
		KeyFactory keyFactory;
		try {
			keyFactory = KeyFactory.getInstance(algorithm);
		} catch (NoSuchAlgorithmException e) {
			log.error("loadPKCS8Privatekey error", e);
			throw e;
		}
		try {
			return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(priKeyPKCS8Der));
		} catch (InvalidKeySpecException e) {
			log.error("loadPKCS8Privatekey error", e);
			throw e;
		}
	}

	/**
	 * 加载PKCS#1标准的RSA公钥
	 *
	 * @param pubKeyPKCS1Decoded PKCS#1标准的RSA公钥
	 * @return Java通用公钥接口
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 * @throws InvalidKeySpecException  无效的密钥规范异常
	 * @throws IOException              IO异常
	 */
	private static PublicKey loadRSAPKCS1PublicKey(byte[] pubKeyPKCS1Decoded) throws InvalidKeySpecException, IOException, NoSuchAlgorithmException {
		// kxz：openssl和Java生成的x509标准的公钥的id都是有两部分（第一部分是下面代码的rsaEncryption，第二个为null），网上的通用方法缺少null部分。在这里做了更正，
		AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
		ASN1Object rsaPKCS1PublicKey = null;
		try {
			rsaPKCS1PublicKey = ASN1Primitive.fromByteArray(pubKeyPKCS1Decoded);
		} catch (IOException e) {
			log.error("loadRSAPKCS1PublicKey error", e);
			throw e;
		}
		SubjectPublicKeyInfo spki;
		try {
			spki = new SubjectPublicKeyInfo(algorithmIdentifier, rsaPKCS1PublicKey);
		} catch (IOException e) {
			log.error("loadRSAPKCS1PublicKey error", e);
			throw e;
		}
		return loadX509Publickey(spki.getEncoded(), TYPE_ALGORITHM_RSA);

	}

	/**
	 * 加载PKCS#1标准的RSA私钥
	 *
	 * @param derPrikeyPKCS1Encoded PKCS#1标准的RSA私钥
	 * @return Java通用私钥接口
	 * @throws IOException              IO异常
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 * @throws InvalidKeySpecException  无效的密钥规范异常
	 */
	private static PrivateKey loadRSAPKCS1PrivateKey(byte[] derPrikeyPKCS1Encoded) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
		// kxz：openssl和Java生成的pkcs8标准的私钥的id都是有两部分（第一部分是下面代码的rsaEncryption，第二个为null），但网上的通用方法缺少null部分。在这里更正了该缺陷，
		AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
		ASN1Object rsaPKCS1PrivateKey;
		try {
			rsaPKCS1PrivateKey = ASN1Primitive.fromByteArray(derPrikeyPKCS1Encoded);
		} catch (IOException e) {
			log.error("loadRSAPKCS1PrivateKey error", e);
			throw e;
		}
		PrivateKeyInfo privateKeyInfo;
		try {
			privateKeyInfo = new PrivateKeyInfo(algorithmIdentifier, rsaPKCS1PrivateKey);
		} catch (IOException e) {
			log.error("loadRSAPKCS1PrivateKey error", e);
			throw e;
		}
		return loadPKCS8Privatekey(privateKeyInfo.getEncoded(), TYPE_ALGORITHM_RSA);
	}

	/**
	 * 加载PKCS#1标准的DSA私钥
	 *
	 * @param priKeyPKCS1Der 编码后的PKCS1私钥数据
	 * @return Java通用私钥接口
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 * @throws InvalidKeySpecException  无效的密钥规范异常
	 */
	private static PrivateKey loadDSAPKCS1PrivateKey(byte[] priKeyPKCS1Der) throws NoSuchAlgorithmException, InvalidKeySpecException {
		DSAPrivateKeyPKCS1 dsaPrivateKey = DSAPrivateKeyPKCS1.getInstance(priKeyPKCS1Der);
		DSAPrivateKeySpec dsaPriKeySpec = new DSAPrivateKeySpec(dsaPrivateKey.getX(), dsaPrivateKey.getP(), dsaPrivateKey.getQ(), dsaPrivateKey.getG());
		KeyFactory keyFactory;
		try {
			keyFactory = KeyFactory.getInstance(TYPE_ALGORITHM_DSA, PROVIDER);
		} catch (NoSuchAlgorithmException e) {
			log.error("loadDSAPKCS1PrivateKey error", e);
			throw e;
		}
		try {
			return keyFactory.generatePrivate(dsaPriKeySpec);
		} catch (InvalidKeySpecException e) {
			log.error("loadDSAPKCS1PrivateKey error", e);
			throw e;
		}
	}

	/**
	 * 加载16进制字符串格式私钥
	 *
	 * @param prvKey 私钥字符串
	 * @return Java通用私钥接口
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 * @throws InvalidKeySpecException  无效的密钥规范异常
	 */
	private static PrivateKey loadSM2HexPrivatekey(String prvKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
		// 获取SM2相关参数
		X9ECParameters parameters = GMNamedCurves.getByName("sm2p256v1");
		// 椭圆曲线参数规格
		ECParameterSpec ecParameterSpec = new ECParameterSpec(parameters.getCurve(), parameters.getG(), parameters.getN(), parameters.getH());
		// 将私钥HEX字符串转换为X值
		BigInteger bigInteger = new BigInteger(prvKey, 16);
		// 获取椭圆曲线KEY生成器
		KeyFactory keyFactory;
		try {
			keyFactory = KeyFactory.getInstance(TYPE_ALGORITHM_EC, PROVIDER);
		} catch (NoSuchAlgorithmException e) {
			log.error("loadSM2HexPrivatekey error", e);
			throw e;
		}
		// 将X值转为私钥KEY对象
		try {
			return keyFactory.generatePrivate(new ECPrivateKeySpec(bigInteger, ecParameterSpec));
		} catch (InvalidKeySpecException e) {
			log.error("loadSM2HexPrivatekey error", e);
			throw e;
		}
	}

	/**
	 * 加载16进制字符串格式公钥
	 *
	 * @param pubKey 公钥字符串
	 * @return Java通用公钥接口
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 * @throws InvalidKeySpecException  无效的密钥规范异常
	 */
	private static PublicKey loadSM2HexPublickey(String pubKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
		// 获取SM2相关参数
		X9ECParameters parameters = GMNamedCurves.getByName("sm2p256v1");
		// 椭圆曲线参数规格
		ECParameterSpec ecParameterSpec = new ECParameterSpec(parameters.getCurve(), parameters.getG(), parameters.getN(), parameters.getH());
		// 将公钥HEX字符串转换为椭圆曲线对应的点
		ECPoint ecPoint = parameters.getCurve().decodePoint(Hex.decode(pubKey));
		// 获取椭圆曲线KEY生成器
		KeyFactory keyFactory;
		try {
			keyFactory = KeyFactory.getInstance(TYPE_ALGORITHM_EC, PROVIDER);
		} catch (NoSuchAlgorithmException e) {
			log.error("loadSM2HexPublickey error", e);
			throw e;
		}
		// 将椭圆曲线点转为公钥KEY对象
		try {
			return keyFactory.generatePublic(new ECPublicKeySpec(ecPoint, ecParameterSpec));
		} catch (InvalidKeySpecException e) {
			log.error("loadSM2HexPublickey error", e);
			throw e;
		}
	}

	/**
	 * 加载《GMT 0010-2012 SM2密码算法加密签名消息语法规范.pdf》规范私钥
	 *
	 * @param derPrikeyGMTEncoded 编码后的GMT私钥
	 * @return Java通用私钥接口
	 * @throws IOException              IO异常
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 * @throws InvalidKeySpecException  无效的密钥规范异常
	 */
	private static PrivateKey loadSM2GMTPrivateKey(byte[] derPrikeyGMTEncoded) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
		AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, GMObjectIdentifiers.sm2p256v1);
		ASN1Object rsaPKCS1PrivateKey;
		try {
			rsaPKCS1PrivateKey = ASN1Primitive.fromByteArray(derPrikeyGMTEncoded);
		} catch (IOException e) {
			log.error("loadSM2GMTPrivateKey error", e);
			throw e;
		}
		PrivateKeyInfo privateKeyInfo;
		try {
			privateKeyInfo = new PrivateKeyInfo(algorithmIdentifier, rsaPKCS1PrivateKey);
		} catch (IOException e) {
			log.error("loadSM2GMTPrivateKey error", e);
			throw e;
		}
		byte[] derPrikeyPKCS8Encoded;
		try {
			derPrikeyPKCS8Encoded = privateKeyInfo.getEncoded();
		} catch (IOException e) {
			log.error("loadSM2GMTPrivateKey error", e);
			throw e;
		}
		return loadPKCS8Privatekey(derPrikeyPKCS8Encoded, TYPE_ALGORITHM_EC);
	}

	/**
	 * 获取X509标准编码的字节数组
	 *
	 * @param publicKey Java通用公钥接口
	 * @return X509标准编码的字节数组
	 */
	private static byte[] getX509PublickeyEncoded(PublicKey publicKey) {
		return publicKey.getEncoded();
	}

	/**
	 * 获取PKCS#8标准编码的字节数组
	 *
	 * @param privateKey Java通用私钥接口
	 * @return PKCS#8标准编码的字节数组
	 */
	private static byte[] getPKCS8PrivatekeyEncoded(PrivateKey privateKey) {
		return privateKey.getEncoded();
	}

	/**
	 * 获取RSA PKCS#1标准编码的字节数组
	 *
	 * @param publicKey Java通用公钥接口
	 * @return RSA PKCS#1标准编码的字节数组
	 * @throws IOException IO异常
	 */
	private static byte[] getRSAPKCS1PublicKeyEncoded(PublicKey publicKey) throws IOException {
		SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
		org.bouncycastle.asn1.pkcs.RSAPublicKey rsaPublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(spki.parsePublicKey());
		try {
			return rsaPublicKey.getEncoded();
		} catch (IOException e) {
			log.error("getRSAPKCS1PublicKeyEncoded error", e);
			throw e;
		}
	}

	/**
	 * 获取RSA PKCS#1标准编码的字节数组
	 *
	 * @param privateKey Java通用私钥接口
	 * @return RSA PKCS#1标准编码的字节数组
	 * @throws IOException IO异常
	 */
	private static byte[] getRSAPKCS1PrivateKeyEncoded(PrivateKey privateKey) throws IOException {
		// 可以通过下列方式由PKCS#8格式转换成PKCS#1格式（也是BC的内置RSAPrivateKey类的编码方式）。本质是采用提取的方式提取出私钥成分，然后实例化。
//		PrivateKeyInfo pki = PrivateKeyInfo.getInstance(privateKey.getEncoded());
//		org.bouncycastle.asn1.pkcs.RSAPrivateKey rsaPrivateKey = org.bouncycastle.asn1.pkcs.RSAPrivateKey.getInstance(pki.parsePrivateKey());
//		return rsaPrivateKey.getEncoded();
		// PKCS#1编码的私钥是PKCS#8编码的私钥的一部分。这里采用直接提取的方式
		PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privateKey.getEncoded());
		ASN1Encodable encodable;
		try {
			encodable = pkInfo.parsePrivateKey();
		} catch (IOException e) {
			log.error("getRSAPKCS1PrivateKeyEncoded error", e);
			throw e;
		}
		ASN1Primitive primitive = encodable.toASN1Primitive();
		try {
			return primitive.getEncoded();
		} catch (IOException e) {
			log.error("getRSAPKCS1PrivateKeyEncoded error", e);
			throw e;
		}
	}

	/**
	 * 获取DSA PKCS#1标准编码的字节数组
	 *
	 * @param privateKey Java通用私钥接口
	 * @return DSA PKCS#1标准编码的字节数组
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 * @throws InvalidKeySpecException  无效的密钥规范异常
	 * @throws IOException              IO异常
	 */
	private static byte[] getDSAPKCS1PrivateKeyEncoded(PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
		DSAPrivateKey priKey = (DSAPrivateKey) loadPKCS8Privatekey(privateKey.getEncoded(), TYPE_ALGORITHM_DSA);
		// y = g^x mod p ，( p, q, g, y )为公钥；
		DSAParams params = priKey.getParams();
		BigInteger p = params.getP();
		BigInteger q = params.getQ();
		BigInteger g = params.getG();
		BigInteger x = priKey.getX();
		BigInteger y = g.modPow(x, p);
		DSAPrivateKeyPKCS1 priKeyPKCS1 = new DSAPrivateKeyPKCS1(p, q, g, y, x);
		try {
			return priKeyPKCS1.getEncoded();
		} catch (IOException e) {
			log.error("getDSAPKCS1PrivateKeyEncoded error", e);
			throw e;
		}
	}

	/**
	 * 获取SM2 Hex编码的字节数组
	 *
	 * @param privateKey Java通用私钥接口
	 * @return SM2 Hex编码的字节数组
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 * @throws InvalidKeySpecException  无效的密钥规范异常
	 */
	private static String getSM2HexPrivatekeyEncoded(PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
		BCECPrivateKey privateSM2Key = (BCECPrivateKey) loadPKCS8Privatekey(privateKey.getEncoded(), TYPE_ALGORITHM_EC);
		String priKeyHex = privateSM2Key.getD().toString(16);
		final int priKeyHexLength = 64;// 固定64
		StringBuilder priKeyHexBuilder = new StringBuilder(priKeyHex);
		while (priKeyHexBuilder.length() < priKeyHexLength) {
			priKeyHexBuilder.append("0");
		}
		return priKeyHexBuilder.toString();
	}

	/**
	 * 获取SM2 Hex编码的字节数组
	 *
	 * @param publicKey Java通用公钥接口
	 * @return SM2 Hex编码的字节数组
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 * @throws InvalidKeySpecException  无效的密钥规范异常
	 */
	private static String getSM2HexPublickeyEncoded(PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
		BCECPublicKey publicSM2Key = (BCECPublicKey) loadX509Publickey(publicKey.getEncoded(), TYPE_ALGORITHM_EC);
		return Hex.toHexString(publicSM2Key.getQ().getEncoded(false));
	}

	/**
	 * 获取SM2 依据《GMT 0010-2012 SM2密码算法加密签名消息语法规范.pdf》编码的字节数组<br>
	 * <br>
	 * OpenSSL适配：对比Java中getEncoded()方法和OpenSSL生成的公私钥，发现公钥格式相同，私钥格式不同。查看2012年2月发布的《GMT
	 * 0010-2012 SM2密码算法加密签名消息语法规范.pdf》，可知OpenSSL符合该规范。
	 * 但有文章表示规范中的定义还不够完善，真正要实现私钥交换的话，还要封装成PKCS#8格式。而Java 默认使用PKCS#8标准<br>
	 * 本方法是从PKCS#8标准的私钥中提取该部分。<br>
	 *
	 * @param privateKey Java通用私钥接口
	 * @return SM2 依据《GMT 0010-2012 SM2密码算法加密签名消息语法规范.pdf》编码的字节数组
	 * @throws IOException IO异常
	 */
	private static byte[] getSM2GMTPrivateKeyEncoded(PrivateKey privateKey) throws IOException {
		PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privateKey.getEncoded());
		ASN1Encodable encodable;
		try {
			encodable = pkInfo.parsePrivateKey();
		} catch (IOException e) {
			log.error("getSM2GMTPrivateKeyEncoded error", e);
			throw e;
		}
		ASN1Primitive primitive = encodable.toASN1Primitive();
		try {
			return primitive.getEncoded();
		} catch (IOException e) {
			log.error("getSM2GMTPrivateKeyEncoded error", e);
			throw e;
		}
	}

	/**
	 * 加载对称密钥，限制AES、SM4、3DES
	 *
	 * @param raw       密钥数组
	 * @param algorithm 密钥算法
	 * @return 对称密钥
	 */
	private static Key loadSecretKey(byte[] raw, String algorithm) {
		if (is3DESAlgorithm(algorithm)) {
			algorithm = TYPE_ALGORITHM_3DES;
		}
		return new SecretKeySpec(raw, algorithm);
	}

	/**
	 * 是否是RSA算法
	 *
	 * @param algorithm 算法名称
	 * @return 是返回ture；不是返回false
	 */
	private static boolean isRSAAlgorithm(String algorithm) {
		return TYPE_ALGORITHM_RSA.equalsIgnoreCase(algorithm);
	}

	/**
	 * 是否是DSA算法
	 *
	 * @param algorithm 算法名称
	 * @return 是返回ture；不是返回false
	 */
	private static boolean isDSAAlgorithm(String algorithm) {
		return TYPE_ALGORITHM_DSA.equalsIgnoreCase(algorithm);
	}

	/**
	 * 是否是SM2算法<br>
	 * SM2基于EC，这里不区分SM2算法和其它参数的EC算法，只研究SM2算法，统一视为SM2算法。
	 *
	 * @param algorithm 算法名称
	 * @return 是返回ture；不是返回false
	 */
	private static boolean isSM2Algorithm(String algorithm) {
		return TYPE_ALGORITHM_SM2.equalsIgnoreCase(algorithm) || TYPE_ALGORITHM_EC.equalsIgnoreCase(algorithm) || TYPE_ALGORITHM_ECDSA.equalsIgnoreCase(algorithm);
	}

	/**
	 * 是否是AES算法
	 *
	 * @param algorithm 算法名称
	 * @return 是返回ture；不是返回false
	 */
	private static boolean isAESAlgorithm(String algorithm) {
		return TYPE_ALGORITHM_AES.equalsIgnoreCase(algorithm);
	}

	/**
	 * 是否是3DES算法
	 *
	 * @param algorithm 算法名称
	 * @return 是返回ture；不是返回false
	 */
	private static boolean is3DESAlgorithm(String algorithm) {
		return TYPE_ALGORITHM_3DES.equalsIgnoreCase(algorithm) || "3DES".equalsIgnoreCase(algorithm);
	}

	/**
	 * 是否是SM4算法<br>
	 * SM2基于EC，这里不区分SM2算法和其它参数的EC算法，只研究SM2算法，统一视为SM2算法。
	 *
	 * @param algorithm 算法名称
	 * @return 是返回ture；不是返回false
	 */
	private static boolean isSM4Algorithm(String algorithm) {
		return TYPE_ALGORITHM_SM4.equalsIgnoreCase(algorithm);
	}

	/**
	 * 生成非对称密钥
	 *
	 * @param algorithm 算法
	 * @param keysize   密钥长度
	 * @return 非对称密钥
	 * @throws NoSuchAlgorithmException           不支持该算法异常
	 * @throws InvalidAlgorithmParameterException 无效的算法参数异常
	 */
	private static KeyPair genKeyPair(String algorithm, int keysize) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
		if (!isRSAAlgorithm(algorithm) && !isDSAAlgorithm(algorithm) && !isSM2Algorithm(algorithm)) {
			log.error("genKeyPair error");
			throw new NoSuchAlgorithmException("算法输入有误，限制RSA、DSA、SM2");
		}
		KeyPairGenerator keyPairGen;
		if (isSM2Algorithm(algorithm)) {
			try {
				keyPairGen = KeyPairGenerator.getInstance(TYPE_ALGORITHM_EC, PROVIDER);
			} catch (NoSuchAlgorithmException e) {
				log.error("genKeyPair error", e);
				throw e;
			}
			// 获取椭圆曲线相关生成参数规格
			ECGenParameterSpec genParameterSpec = new ECGenParameterSpec("sm2p256v1");
			try {
				keyPairGen.initialize(genParameterSpec, new SecureRandom());
			} catch (InvalidAlgorithmParameterException e) {
				log.error("genKeyPair error", e);
				throw e;
			}
		} else {
			try {
				keyPairGen = KeyPairGenerator.getInstance(algorithm);
			} catch (NoSuchAlgorithmException e) {
				log.error("genKeyPair error", e);
				throw e;
			}
			keyPairGen.initialize(keysize, new SecureRandom());
		}

		// 生成一个密钥对，保存在keyPair中
		return keyPairGen.generateKeyPair();
	}

	/**
	 * 加密私钥
	 *
	 * @param priKeyPKCS8Pem 私钥
	 * @param algorithm      算法
	 * @param password       口令/密码
	 * @return 加密后的PKCS#8标准、PEM格式的私钥
	 * @throws NoSuchAlgorithmException           不支持该算法异常
	 * @throws InvalidKeySpecException            无效的密钥规范异常
	 * @throws NoSuchPaddingException             不支持填充方式异常
	 * @throws InvalidAlgorithmParameterException 无效的算法参数异常
	 * @throws InvalidKeyException                无效的密钥异常
	 * @throws BadPaddingException                错误的填充方式异常
	 * @throws IllegalBlockSizeException          不合法的块大小异常
	 * @throws InvalidParameterSpecException      无效的参数规范异常
	 * @throws IOException                        IO异常
	 */
	private static String encryptPKCS8PrivateKey(String priKeyPKCS8Pem, String algorithm, String password) 
			throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, InvalidParameterSpecException {
		PrivateKey priKey = loadPKCS8Privatekey(pemToDer(priKeyPKCS8Pem), algorithm);
		// extract the encoded private key, this is an unencrypted PKCS#8 private key
		byte[] encodedprivkey = getPKCS8PrivatekeyEncoded(priKey);

		// We must use a PasswordBasedEncryption algorithm in order to encrypt the
		// private key, you may use any common algorithm supported by openssl, you can
		// check them in the openssl documentation
		// http://www.openssl.org/docs/apps/pkcs8.html
		String MYPBEALG = "PBEWithSHA1AndDESede";// 算法暂时指定PBEWithSHA1AndDESede，不可更改

		int count = 20;// hash iteration count
		SecureRandom random = new SecureRandom();
		byte[] salt = new byte[8];
		random.nextBytes(salt);
		// Create PBE parameter set
		PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, count);
		PBEKeySpec pbeKeySpec1 = new PBEKeySpec(password.toCharArray());
		SecretKeyFactory keyFac;
		try {
			keyFac = SecretKeyFactory.getInstance(MYPBEALG);
		} catch (NoSuchAlgorithmException e) {
			log.error("encryptPKCS8PrivateKey error", e);
			throw e;
		}
		SecretKey pbeKey1;
		try {
			pbeKey1 = keyFac.generateSecret(pbeKeySpec1);
		} catch (InvalidKeySpecException e) {
			log.error("encryptPKCS8PrivateKey error", e);
			throw new InvalidKeySpecException(e);
		}

		Cipher pbeCipher;
		try {
			pbeCipher = Cipher.getInstance(MYPBEALG);
		} catch (NoSuchAlgorithmException|NoSuchPaddingException e) {
			log.error("encryptPKCS8PrivateKey error", e);
			throw e;
		} 

		// Initialize PBE Cipher with key and parameters
		try {
			pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey1, pbeParamSpec);
		} catch (InvalidKeyException|InvalidAlgorithmParameterException e) {
			log.error("encryptPKCS8PrivateKey error", e);
			throw e;
		} 

		// Encrypt the encoded Private Key with the PBE key
		byte[] ciphertext;
		try {
			ciphertext = pbeCipher.doFinal(encodedprivkey);
		} catch (IllegalBlockSizeException |BadPaddingException e) {
			log.error("encryptPKCS8PrivateKey error", e);
			throw e;
		} 

		// Now construct PKCS #8 EncryptedPrivateKeyInfo object
		AlgorithmParameters algparms;
		try {
			algparms = AlgorithmParameters.getInstance(MYPBEALG);
		} catch (NoSuchAlgorithmException e) {
			log.error("encryptPKCS8PrivateKey error", e);
			throw e;
		}
		try {
			algparms.init(pbeParamSpec);
		} catch (InvalidParameterSpecException e) {
			log.error("encryptPKCS8PrivateKey error", e);
			throw e;
		}
		EncryptedPrivateKeyInfo encinfo;
		try {
			encinfo = new EncryptedPrivateKeyInfo(algparms, ciphertext);
		} catch (NoSuchAlgorithmException e) {
			log.error("encryptPKCS8PrivateKey error", e);
			throw e;
		}

		// and here we have it! a DER encoded PKCS#8 encrypted key!
		byte[] encryptedPkcs8;
		try {
			encryptedPkcs8 = encinfo.getEncoded();
		} catch (IOException e) {
			log.error("encryptPKCS8PrivateKey error", e);
			throw e;
		}
		return derToPem(TYPE_PREFIX_PKCS8_ENCRYPTED_PRIVATE_KEY, encryptedPkcs8);
	}

	/**
	 * 解密PKCS#8私钥
	 *
	 * @param priKeyPKCS8EncryptedPem 加密后的PKCS#8标准、PEM格式的私钥
	 * @param algorithm               算法
	 * @param password                口令/密码
	 * @return PKCS#8私钥
	 * @throws IOException                        IO异常
	 * @throws NoSuchAlgorithmException           不支持该算法异常
	 * @throws NoSuchPaddingException             不支持填充方式异常
	 * @throws InvalidKeySpecException            无效的密钥规范异常
	 * @throws InvalidKeyException                无效的密钥异常
	 * @throws InvalidAlgorithmParameterException 无效的算法参数异常
	 */
	private static String decryptPKCS8PrivateKey(String priKeyPKCS8EncryptedPem, String algorithm, String password) 
			throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException
			 {
		EncryptedPrivateKeyInfo encryptPKInfo = new EncryptedPrivateKeyInfo(pemToDer(priKeyPKCS8EncryptedPem));
		Cipher cipher;
		try {
			cipher = Cipher.getInstance(encryptPKInfo.getAlgName());
		} catch (NoSuchAlgorithmException|NoSuchPaddingException e) {
			log.error("decryptPKCS8PrivateKey error", e);
			throw e;
		} 
		PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
		SecretKeyFactory secFac;
		try {
			secFac = SecretKeyFactory.getInstance(encryptPKInfo.getAlgName());
		} catch (NoSuchAlgorithmException e) {
			log.error("decryptPKCS8PrivateKey error", e);
			throw e;
		}
		Key pbeKey;
		try {
			pbeKey = secFac.generateSecret(pbeKeySpec);
		} catch (InvalidKeySpecException e) {
			log.error("decryptPKCS8PrivateKey error", e);
			throw e;
		}
		AlgorithmParameters algParams = encryptPKInfo.getAlgParameters();
		try {
			cipher.init(Cipher.DECRYPT_MODE, pbeKey, algParams);
		} catch (InvalidKeyException|InvalidAlgorithmParameterException e) {
			log.error("decryptPKCS8PrivateKey error", e);
			throw e;
		}
		KeySpec pkcs8KeySpec;
		try {
			pkcs8KeySpec = encryptPKInfo.getKeySpec(cipher);
		} catch (InvalidKeySpecException e) {
			log.error("decryptPKCS8PrivateKey error", e);
			throw e;
		}
		KeyFactory kf;
		try {
			kf = KeyFactory.getInstance(algorithm);
		} catch (NoSuchAlgorithmException e) {
			log.error("decryptPKCS8PrivateKey error", e);
			throw e;
		}
		PrivateKey priKey;
		try {
			priKey = kf.generatePrivate(pkcs8KeySpec);
		} catch (InvalidKeySpecException e) {
			log.error("decryptPKCS8PrivateKey error", e);
			throw e;
		}
		return derToPem(TYPE_PREFIX_PKCS8_PRIVATE_KEY, priKey.getEncoded());
	}

	/**
	 * 加密OpenSSL私钥
	 * 
	 * @param openSSLKeyPairPem pem格式OpenSSL私钥
	 * @param password          私钥密码
	 * @return 加密后的Pem格式的OpenSSL私钥
	 * @throws IOException IO异常
	 */
	private static String encrytOpenSSLPrivateKey(String openSSLKeyPairPem, String password) throws IOException  {
		try {
			// 读取Pem
	        PEMParser pemParser = new PEMParser(new StringReader(openSSLKeyPairPem));
	        Object object = pemParser.readObject();
	        // 加密
	        StringWriter stringWriter = new StringWriter();// 输出
	        JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter);
	        PEMEncryptor encryptor = new JcePEMEncryptorBuilder("DES-EDE3-CBC").setProvider("BC").build(password.toCharArray());
	        JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
	        if (object instanceof PEMKeyPair) {
	            object = converter.getKeyPair((PEMKeyPair) object).getPrivate();
	        }
	        pemWriter.writeObject(object, encryptor);
	        pemWriter.close();
	        return stringWriter.toString();
		}catch (IOException e) {
			log.error("encrytOpenSSLPrivateKey error",e);
			throw e;
		}
		 
	}

	/**
	 * 解密OpenSSL私钥
	 * 
	 * @param openSSLKeyPairEncryptedPem 加密后的Pem格式的OpenSSL私钥
	 * @param password                   私钥密码
	 * @return 解密后的OpenSSL私钥
	 * @throws IOException              IO异常
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 * @throws InvalidKeySpecException  无效的密钥规范异常
	 */
	private static String decryptOpensslPrivateKey(String openSSLKeyPairEncryptedPem, String password) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException   {
		Object object;
		try (PEMParser pemParser = new PEMParser(new StringReader(openSSLKeyPairEncryptedPem))) {
			object = pemParser.readObject();
		} catch (IOException e) {
			log.error("decryptOpensslPrivateKey error",e);
			throw e;
		}

		PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
		JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
		KeyPair kp;
		if (object instanceof PEMEncryptedKeyPair) {
			try {
				kp = converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv));
			} catch (IOException e) {
				log.error("decryptOpensslPrivateKey error",e);
				throw e;
			}
		} else {
			try {
				kp = converter.getKeyPair((PEMKeyPair) object);
			} catch (PEMException e) {
				log.error("decryptOpensslPrivateKey error",e);
				throw e;
			}
		}
		String algorithm = kp.getPrivate().getAlgorithm();
		Map<String, Object> map = getKeyPairMap(kp);

		if (isRSAAlgorithm(algorithm) || isDSAAlgorithm(algorithm)) {
			return (String) map.get("priKeyPKCS1Pem");
		} else {
			return (String) map.get("priKeyGMTPem");
		}
	}

	/**
	 * 生成对称密钥<br>
	 * 对称密钥已知三种派生方式：Java的安全随机数SecureRandom、Java的密钥生成器KeyGenerator、基于口令的密钥派生函数PBKDF2。KeyGenerator基于SecureRandom。PBKDF2需要指定口令、盐值、迭代次数、密钥长度。PBKDF2更安全，但是前两者也已能满足需求。<br>
	 *
	 * @param algorithm 算法
	 * @param keySize   密钥长度
	 * @param password  口令
	 * @param salt      盐值
	 * @return 对称密钥
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 * @throws InvalidKeySpecException  无效的密钥规范异常
	 */
	private static SecretKey genSecretKey(String algorithm, int keySize, String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
		if (!(isAESAlgorithm(algorithm) || is3DESAlgorithm(algorithm) || isSM4Algorithm(algorithm))) {
			log.info("算法输入有误，限制AES、3DES、SM4。实际输入为：" + algorithm);
			throw new NoSuchAlgorithmException("算法输入有误，限制AES、3DES、SM4");
		}
		if (StringUtils.isEmpty(password)) {

			algorithm = is3DESAlgorithm(algorithm) ? TYPE_ALGORITHM_3DES : algorithm;
			KeyGenerator kg;
			try {
				kg = KeyGenerator.getInstance(algorithm);
			} catch (NoSuchAlgorithmException e) {
				log.error("genSecretKey error",e);
				throw e;
			}
			kg.init(keySize, new SecureRandom());
			// 生成一个密钥
			return kg.generateKey();

		} else {
			/* Derive the key, given password and salt. */
			SecretKeyFactory factory;
			try {
				factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
			} catch (NoSuchAlgorithmException e) {
				log.error("genSecretKey error",e);
				throw e;
			}
			KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, keySize);
			try {
				return factory.generateSecret(spec);
			} catch (InvalidKeySpecException e) {
				log.error("genSecretKey error",e);
				throw e;
			}

		}
	}

	/**
	 * 获取密钥的表现形式
	 *
	 * @param keyPair 密钥对
	 * @return 密钥对Map
	 * @throws IOException              IO异常
	 * @throws InvalidKeySpecException  无效的密钥规范异常
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 */
	private static Map<String, Object> getKeyPairMap(KeyPair keyPair) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException   {
		Map<String, Object> key = new HashMap<>();

		// Java内置getEncoded()方法私钥默认PKCS#8标准，公钥默认X.509标准
		PrivateKey priKey = keyPair.getPrivate();
		byte[] priKeyPKCS8Der = getPKCS8PrivatekeyEncoded(priKey);
		String priKeyPKCS8Str = derToStr(priKeyPKCS8Der);
		String priKeyPKCS8Pem = derToPem(TYPE_PREFIX_PKCS8_PRIVATE_KEY, priKeyPKCS8Der);
		key.put("priKeyPKCS8Der", priKeyPKCS8Der);
		key.put("priKeyPKCS8Str", priKeyPKCS8Str);
		key.put("priKeyPKCS8Pem", priKeyPKCS8Pem);

		PublicKey pubKey = keyPair.getPublic();
		byte[] pubKeyX509Der = getX509PublickeyEncoded(pubKey);
		String pubKeyX509Str = derToStr(pubKeyX509Der);
		String pubKeyX509Pem = derToPem(TYPE_PREFIX_X509_PUBLIC_KEY, pubKeyX509Der);
		key.put("pubKeyX509Der", pubKeyX509Der);
		key.put("pubKeyX509Str", pubKeyX509Str);
		key.put("pubKeyX509Pem", pubKeyX509Pem);

		// RSA算法密钥适用PKCS#1标准
		if (isRSAAlgorithm(priKey.getAlgorithm())) {
			byte[] priKeyPKCS1Der = getRSAPKCS1PrivateKeyEncoded(priKey);
			String priKeyPKCS1Str = derToStr(priKeyPKCS1Der);
			String priKeyPKCS1Pem = derToPem(TYPE_PREFIX_RSA_PKCS1_PRIVATE_KEY, priKeyPKCS1Der);
			key.put("priKeyPKCS1Der", priKeyPKCS1Der);
			key.put("priKeyPKCS1Str", priKeyPKCS1Str);
			key.put("priKeyPKCS1Pem", priKeyPKCS1Pem);

			byte[] pubKeyPKCS1Der = getRSAPKCS1PublicKeyEncoded(pubKey);
			String pubKeyPKCS1Str = derToStr(pubKeyPKCS1Der);
			String pubKeyPKCS1Pem = derToPem(TYPE_PREFIX_RSA_PKCS1_PUBLIC_KEY, pubKeyPKCS1Der);
			key.put("pubKeyPKCS1Der", pubKeyPKCS1Der);
			key.put("pubKeyPKCS1Str", pubKeyPKCS1Str);
			key.put("pubKeyPKCS1Pem", pubKeyPKCS1Pem);
		}

		// DSA算法解析
		if (isDSAAlgorithm(priKey.getAlgorithm())) {
			byte[] priKeyPKCS1Der = getDSAPKCS1PrivateKeyEncoded(priKey);
			String priKeyPKCS1Str = derToStr(priKeyPKCS1Der);
			String priKeyPKCS1Pem = derToPem(TYPE_PREFIX_DSA_PKCS1_PRIVATE_KEY, priKeyPKCS1Der);
			key.put("priKeyPKCS1Der", priKeyPKCS1Der);
			key.put("priKeyPKCS1Str", priKeyPKCS1Str);
			key.put("priKeyPKCS1Pem", priKeyPKCS1Pem);
		}

		if (isSM2Algorithm(priKey.getAlgorithm())) {
			// SM2算法的密钥常用Hex格式表示。在这里将曲线的公共点Q作为公钥、私有数字D作为了私钥
			String priKeyHex = getSM2HexPrivatekeyEncoded(priKey);
			String pubKeyHex = getSM2HexPublickeyEncoded(pubKey);
			key.put("priKeyHex", priKeyHex);
			key.put("pubKeyHex", pubKeyHex);
			// OpenSSL适配
			byte[] priKeyGMTDer = getSM2GMTPrivateKeyEncoded(priKey);
			String priKeyGMTStr = derToStr(priKeyGMTDer);
			String priKeyGMTPem = derToPem(TYPE_PREFIX_SM2_GMT_PRIVATE_KEY, priKeyGMTDer);
			key.put("priKeyGMTDer", priKeyGMTDer);
			key.put("priKeyGMTStr", priKeyGMTStr);
			key.put("priKeyGMTPem", priKeyGMTPem);
		}
		return key;
	}

	/**
	 * 获取密钥的表现形式
	 *
	 * @param secretKey 对称密钥
	 * @return 对称密钥Map
	 */
	private static Map<String, Object> getSecretKeyMap(SecretKey secretKey) {
		byte[] secretKeyDer = secretKey.getEncoded();
		String secretKeyHex = Hex.toHexString(secretKeyDer);
		String secretKeyBase64 = Base64.getEncoder().encodeToString(secretKeyDer);

		Map<String, Object> key = new HashMap<>(3);
		key.put("secretKeyDer", secretKeyDer);
		key.put("secretKeyHex", secretKeyHex);
		key.put("secretKeyBase64", secretKeyBase64);

		return key;
	}

	/**
	 * 数据加密<br>
	 * <br>
	 * 若使用CBC加密模式，可在params中指定IV，指定方式：IvParameterSpec iv = new IvParameterSpec(iv);
	 * params.setParams(iv);若不指定，系统将随机生成IV值。
	 *
	 * @param plaintextArray 明文数组
	 * @param key            对称密钥
	 * @param algorithm      算法
	 * @param mode           加密模式
	 * @param padding        填充方式
	 * @param iv             偏移量
	 * @return 加密结果Map，包含密文、偏移量等值。<br>
	 * @throws NoSuchAlgorithmException           不支持该算法异常
	 * @throws NoSuchPaddingException             不支持填充方式异常
	 * @throws InvalidKeyException                无效的密钥异常
	 * @throws IllegalBlockSizeException          不合法的块大小异常
	 * @throws BadPaddingException                错误的填充方式异常
	 * @throws InvalidAlgorithmParameterException 无效的算法参数异常
	 */
	private static Map<String, String> encrypt(byte[] plaintextArray, Key key, String algorithm, String mode, String padding, String iv) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
			 {
		Map<String, String> map = new HashMap<>();// 返回值
		Cipher cipher;
		if (isSM2Algorithm(algorithm)) {
			algorithm = TYPE_ALGORITHM_SM2;
		}
		String transformation = StringUtils.isEmpty(mode) ? algorithm : algorithm + "/" + mode + "/" + padding;
		if (isSM2Algorithm(algorithm) || isSM4Algorithm(algorithm)) {
			try {
				cipher = Cipher.getInstance(transformation, PROVIDER);
			} catch (NoSuchAlgorithmException e) {
				log.error("encrypt error",e);
				throw e;
			} catch (NoSuchPaddingException e) {
				log.error("encrypt error",e);
				throw e;
			}// 国密算法指定provider
		} else {
			try {
				cipher = Cipher.getInstance(transformation);
			} catch (NoSuchAlgorithmException|NoSuchPaddingException e) {
				log.error("encrypt error",e);
				throw e;
			}
		}
		// CBC模式需要IV值
		if (TYPE_MODE_CBC.equalsIgnoreCase(mode)) {
			if (StringUtils.isEmpty(iv)) {
				SecureRandom s = new SecureRandom();
				byte[] ivBytes;
				// IV值估计和密钥长度有关，先写死，后续继续研究
				if (is3DESAlgorithm(algorithm)) {
					ivBytes = new byte[8];
				} else {
					ivBytes = new byte[16];
				}
				s.nextBytes(ivBytes);
				iv = Hex.toHexString(ivBytes);
			}
			IvParameterSpec ivParameterSpec = new IvParameterSpec(Hex.decode(iv));
			try {
				cipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);
			} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
				log.error("encrypt error",e);
				throw e;
			}
			map.put("iv", iv);
		} else {
			try {
				cipher.init(Cipher.ENCRYPT_MODE, key);
			} catch (InvalidKeyException e) {
				log.error("loadPKCS8Privatekey error",e);
				throw e;
			}
		}
		byte[] ciphertextArray;
		try {
			ciphertextArray = cipher.doFinal(plaintextArray);
		} catch (IllegalBlockSizeException | BadPaddingException e) {
			log.error("loadPKCS8Privatekey error",e);
			throw e;
		}
		map.put("ciphertextHex", Hex.toHexString(ciphertextArray));
		map.put("ciphertextBase64", Base64.getEncoder().encodeToString(ciphertextArray));

		return map;
	}

	/**
	 * 数据解密
	 *
	 * @param ciphertextArray 密文数组
	 * @param key             密钥
	 * @param algorithm       算法
	 * @param mode            加密模式，CBC模式IV值不能为null
	 * @param padding         填充方式
	 * @param iv              偏移量，只有CBC模式需要赋值
	 * @return 明文数组 
	 * @throws NoSuchAlgorithmException           不支持该算法异常
	 * @throws NoSuchPaddingException             不支持填充方式异常
	 * @throws InvalidKeyException                无效的密钥异常
	 * @throws IllegalBlockSizeException          不合法的块大小异常
	 * @throws BadPaddingException                错误的填充方式异常
	 * @throws InvalidAlgorithmParameterException 无效的算法参数异常
	 */
	private static byte[] decrypt(byte[] ciphertextArray, Key key, String algorithm, String mode, String padding, String iv) 
			throws NoSuchAlgorithmException,NoSuchPaddingException,InvalidKeyException,InvalidAlgorithmParameterException,IllegalBlockSizeException,BadPaddingException
			  {
		Cipher cipher;
		if (isSM2Algorithm(algorithm)) {
			algorithm = TYPE_ALGORITHM_SM2;
		}
		String transformation = StringUtils.isEmpty(mode) ? algorithm : algorithm + "/" + mode + "/" + padding;
		if (isSM2Algorithm(algorithm) || isSM4Algorithm(algorithm)) {
			try {
				cipher = Cipher.getInstance(transformation, PROVIDER);
			} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
				log.error("decrypt error",e);
				throw e;
			}// 国密算法指定provider
		} else {
			try {
				cipher = Cipher.getInstance(transformation);
			} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
				log.error("decrypt error",e);
				throw e;
			}
		}
		if (TYPE_MODE_CBC.equalsIgnoreCase(mode)) {
			IvParameterSpec ivParameterSpec = new IvParameterSpec(Hex.decode(iv));
			try {
				cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
			} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
				log.error("decrypt error",e);
				throw e;
			}
		} else {
			try {
				cipher.init(Cipher.DECRYPT_MODE, key);
			} catch (InvalidKeyException e) {
				log.error("decrypt error",e);
				throw e;
			}
		}
		try {
			return cipher.doFinal(ciphertextArray);
		} catch (IllegalBlockSizeException | BadPaddingException e) {
			log.error("decrypt error",e);
			throw e;
		}
	}

	/**
	 * 哈希计算
	 *
	 * @param plaintext 明文
	 * @param algorithm 算法
	 * @return 哈希值
	 * @throws NoSuchAlgorithmException 不支持该算法异常
	 */
	private static byte[] hash(byte[] plaintext, String algorithm) throws NoSuchAlgorithmException  {
		if (TYPE_ALGORITHM_SM3.equalsIgnoreCase(algorithm)) {
			MessageDigest messageDigest;
			try {
				messageDigest = MessageDigest.getInstance(TYPE_ALGORITHM_SM3, PROVIDER);
			} catch (NoSuchAlgorithmException e) {
				log.error("hash error",e);
				throw e;
			}
			messageDigest.update(plaintext);
			return messageDigest.digest();
		} else {
			MessageDigest messageDigest;
			try {
				messageDigest = MessageDigest.getInstance(algorithm);
			} catch (NoSuchAlgorithmException e) {
				log.error("hash error",e);
				throw e;
			}
			messageDigest.update(plaintext);
			return messageDigest.digest();
		}
	}

	/**
	 * 签名
	 *
	 * @param plaintextArray 待签名明文
	 * @param privateKey     私钥
	 * @param algorithm      算法，比如SHA1WithRSA
	 * @return 签名
	 * @throws NoSuchAlgorithmException           不支持该算法异常
	 * @throws InvalidKeyException                无效的密钥异常
	 * @throws SignatureException                 签名异常
	 * @throws InvalidAlgorithmParameterException 无效的算法参数异常
	 */
	private static byte[] sign(byte[] plaintextArray, PrivateKey privateKey, String algorithm) throws NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException, SignatureException{
		Signature signature;
		if (isSM2Algorithm(privateKey.getAlgorithm())) {
			try {
				signature = Signature.getInstance(algorithm, PROVIDER);
			} catch (NoSuchAlgorithmException e) {
				log.error("sign error",e);
				throw e;
			}
		} else {
			try {
				signature = Signature.getInstance(algorithm);
			} catch (NoSuchAlgorithmException e) {
				log.error("sign error",e);
				throw e;
			}
		}
		try {
			signature.initSign(privateKey);
		} catch (InvalidKeyException e) {
			log.error("sign error",e);
			throw e;
		}
		if (isSM2Algorithm(privateKey.getAlgorithm())) {
			// UserID
			SM2ParameterSpec spec = new SM2ParameterSpec("1234567812345678".getBytes(StandardCharsets.UTF_8));
			try {
				signature.setParameter(spec);
			} catch (InvalidAlgorithmParameterException e) {
				log.error("sign error",e);
				throw e;
			}
		}
		try {
			signature.update(plaintextArray);
		} catch (SignatureException e) {
			log.error("sign error",e);
			throw e;
		}
		try {
			return signature.sign();
		} catch (SignatureException e) {
			log.error("sign error",e);
			throw e;
		}
	}

	/**
	 * 验签
	 *
	 * @param plaintextArray 明文
	 * @param signatureArray 签名
	 * @param publicKey      公钥
	 * @param algorithm      算法
	 * @return 验签结果
	 * @throws NoSuchAlgorithmException           不支持该算法异常
	 * @throws InvalidKeyException                无效的密钥异常
	 * @throws SignatureException                 签名异常
	 * @throws InvalidAlgorithmParameterException 无效的算法参数异常
	 */
	private static boolean verify(byte[] plaintextArray, byte[] signatureArray, PublicKey publicKey, String algorithm) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, SignatureException, InvalidKeyException  {
		Signature signature;
		if (isSM2Algorithm(publicKey.getAlgorithm())) {
			try {
				signature = Signature.getInstance(algorithm, PROVIDER);
			} catch (NoSuchAlgorithmException e) {
				log.error("verify error",e);
				throw e;
			}
		} else {
			try {
				signature = Signature.getInstance(algorithm);
			} catch (NoSuchAlgorithmException e) {
				log.error("verify error",e);
				throw e;
			}
		}
		try {
			signature.initVerify(publicKey);
		} catch (InvalidKeyException e) {
			log.error("verify error",e);
			throw e;
		}
		if (isSM2Algorithm(publicKey.getAlgorithm())) {
			// UserID
			SM2ParameterSpec spec = new SM2ParameterSpec("1234567812345678".getBytes(StandardCharsets.UTF_8));
			try {
				signature.setParameter(spec);
			} catch (InvalidAlgorithmParameterException e) {
				log.error("verify error",e);
				throw e;
			}
		}
		try {
			signature.update(plaintextArray);
		} catch (SignatureException e) {
			log.error("verify error",e);
			throw e;
		}
		try {
			return signature.verify(signatureArray);
		} catch (SignatureException e) {
			log.error("verify error",e);
			throw e;
		}
	}

	/**
	 * 获取密钥格式
	 * @param pemKey pem格式密钥
	 * @return 密钥格式
	 */
	public static String getKeyFormat(String pemKey) {
		pemKey=pemKey.trim();
		String firstLine=pemKey.replaceAll("(\r\n|\r|\n|\n\r)", "\n").split("\n")[0].replace("-----BEGIN ", "").replace("-----", "");
		String keyFormat="";
		switch(firstLine) {
			case TYPE_PREFIX_PKCS8_PRIVATE_KEY:// PKCS#8前缀
				keyFormat= AsymmetricCommonPrivateKeyFormatType.Pkcs8.name();
				break;
			case TYPE_PREFIX_X509_PUBLIC_KEY:// X509前缀
				keyFormat= AsymmetricPublicKeyFormatType.X509.name();
				break;
			case TYPE_PREFIX_RSA_PKCS1_PRIVATE_KEY:// RSA私钥前缀
				keyFormat= AsymmetricCommonPrivateKeyFormatType.Pkcs1.name();
				break;
			case TYPE_PREFIX_RSA_PKCS1_PUBLIC_KEY:// RSA公钥前缀
				keyFormat= AsymmetricPublicKeyFormatType.Pkcs1.name();
				break;
			case TYPE_PREFIX_DSA_PKCS1_PRIVATE_KEY:// DSA私钥前缀
				keyFormat= AsymmetricCommonPrivateKeyFormatType.Pkcs1.name();
				break;
			case TYPE_PREFIX_SM2_GMT_PRIVATE_KEY:// EC私钥前缀
				keyFormat= AsymmetricSM2PrivateKeyFormatType.GMT.name();
				break;
			case TYPE_PREFIX_PKCS8_ENCRYPTED_PRIVATE_KEY:// 口令加密私钥的前缀
				keyFormat= AsymmetricSM2PrivateKeyFormatType.Pkcs8.name();
				break;
			default:
				break;
		}
		return keyFormat;
		
	}
	
	
	/**
	 * 验证密钥是否被口令加密
	 * @param pemKey Pem格式密钥
	 * @return 加密返回true，未加密返回false
	 */
	public static boolean isEncryptedPemKey(String pemKey) {
		Object object;
		try (PEMParser pemParser = new PEMParser(new StringReader(pemKey))) {
			object = pemParser.readObject();
		} catch (IOException e) {
			log.error("isEncryptedPemKey error",e);
			return false;
		}
		if(object instanceof PEMEncryptedKeyPair || object instanceof PKCS8EncryptedPrivateKeyInfo ) {
			return true;
		}
		return false;
	}
	
	
	/**
	 * 生成密钥
	 *
	 * @param keyGenParams 密钥生成参数
	 * @throws InvalidAlgorithmParameterException 无效的算法参数异常
	 * @throws NoSuchAlgorithmException           不支持该算法异常
	 * @throws IOException                        IO异常
	 * @throws InvalidKeySpecException            无效的密钥规范异常
	 * @throws InvalidParameterSpecException      无效的参数规范异常
	 * @throws BadPaddingException                错误的填充方式异常
	 * @throws IllegalBlockSizeException          不合法的块大小异常
	 * @throws NoSuchPaddingException             不支持填充方式异常
	 * @throws InvalidKeyException                无效的密钥异常
	 */
	public static void genKey(KeyGenParams keyGenParams)
			throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeySpecException, IOException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidParameterSpecException {
		if (keyGenParams instanceof RSAKeyGenParams) {
			RSAKeyGenParams rsaKeyGenParams = (RSAKeyGenParams) keyGenParams;
			KeyPair rsaKey = genKeyPair(TYPE_ALGORITHM_RSA, rsaKeyGenParams.getKeySize());
			Map<String, Object> map = getKeyPairMap(rsaKey);
			// 密码若存在则对该密钥加密
			if (Strings.isNullOrEmpty(rsaKeyGenParams.getPassword())) {
				rsaKeyGenParams.setPriKeyPKCS8Pem((String) map.get("priKeyPKCS8Pem"));
				rsaKeyGenParams.setPriKeyPKCS1Pem((String) map.get("priKeyPKCS1Pem"));
			} else {
				rsaKeyGenParams.setPriKeyPKCS8Pem(encryptPKCS8PrivateKey((String) map.get("priKeyPKCS8Pem"), TYPE_ALGORITHM_RSA, rsaKeyGenParams.getPassword()));
				rsaKeyGenParams.setPriKeyPKCS1Pem(encrytOpenSSLPrivateKey((String) map.get("priKeyPKCS1Pem"), rsaKeyGenParams.getPassword()));
			}
			rsaKeyGenParams.setPubKeyPKCS1Pem((String) map.get("pubKeyPKCS1Pem"));
			rsaKeyGenParams.setPubKeyX509Pem((String) map.get("pubKeyX509Pem"));
		} else if (keyGenParams instanceof DSAKeyGenParams) {
			DSAKeyGenParams dsaKeyGenParams = (DSAKeyGenParams) keyGenParams;
			KeyPair rsaKey = genKeyPair(TYPE_ALGORITHM_DSA, dsaKeyGenParams.getKeySize());
			Map<String, Object> map = getKeyPairMap(rsaKey);
			// 密码若存在则对该密钥加密
			if (Strings.isNullOrEmpty(dsaKeyGenParams.getPassword())) {
				dsaKeyGenParams.setPriKeyPKCS8Pem((String) map.get("priKeyPKCS8Pem"));
				dsaKeyGenParams.setPriKeyPKCS1Pem((String) map.get("priKeyPKCS1Pem"));
			} else {
				dsaKeyGenParams.setPriKeyPKCS8Pem(encryptPKCS8PrivateKey((String) map.get("priKeyPKCS8Pem"), TYPE_ALGORITHM_DSA, dsaKeyGenParams.getPassword()));
				dsaKeyGenParams.setPriKeyPKCS1Pem(encrytOpenSSLPrivateKey((String) map.get("priKeyPKCS1Pem"), dsaKeyGenParams.getPassword()));
			}
			dsaKeyGenParams.setPubKeyX509Pem((String) map.get("pubKeyX509Pem"));
		} else if (keyGenParams instanceof SM2KeyGenParams) {
			SM2KeyGenParams sm2KeyGenParams = (SM2KeyGenParams) keyGenParams;
			KeyPair sm2Key = genKeyPair(TYPE_ALGORITHM_EC, 0);
			Map<String, Object> map = getKeyPairMap(sm2Key);
			// 密码若存在则对该密钥加密
			if (Strings.isNullOrEmpty(sm2KeyGenParams.getPassword())) {
				sm2KeyGenParams.setPriKeyPKCS8Pem((String) map.get("priKeyPKCS8Pem"));
				sm2KeyGenParams.setPriKeyGMTPem((String) map.get("priKeyGMTPem"));
			} else {
				sm2KeyGenParams.setPriKeyPKCS8Pem(encryptPKCS8PrivateKey((String) map.get("priKeyPKCS8Pem"), TYPE_ALGORITHM_EC, sm2KeyGenParams.getPassword()));
				sm2KeyGenParams.setPriKeyGMTPem(encrytOpenSSLPrivateKey((String) map.get("priKeyGMTPem"), sm2KeyGenParams.getPassword()));
			}
			sm2KeyGenParams.setPubKeyX509Pem((String) map.get("pubKeyX509Pem"));
			sm2KeyGenParams.setPriKeyHexFromD((String) map.get("priKeyHex"));
			sm2KeyGenParams.setPubKeyHexFromQ((String) map.get("pubKeyHex"));
		} else if (keyGenParams instanceof AESKeyGenParams) {
			AESKeyGenParams aesKeyGenParams = (AESKeyGenParams) keyGenParams;
			SecretKey aesKey = genSecretKey(aesKeyGenParams.getAlgorithm(), aesKeyGenParams.getKeySize(), null, null);
			Map<String, Object> map = getSecretKeyMap(aesKey);
			aesKeyGenParams.setKeyBase64((String) map.get("secretKeyBase64"));
			aesKeyGenParams.setKeyHex((String) map.get("secretKeyHex"));
		} else if (keyGenParams instanceof DES3KeyGenParams) {
			DES3KeyGenParams des3KeyGenParams = (DES3KeyGenParams) keyGenParams;
			SecretKey aesKey = genSecretKey(des3KeyGenParams.getAlgorithm(), des3KeyGenParams.getKeySize(), null, null);
			Map<String, Object> map = getSecretKeyMap(aesKey);
			des3KeyGenParams.setKeyBase64((String) map.get("secretKeyBase64"));
			des3KeyGenParams.setKeyHex((String) map.get("secretKeyHex"));
		} else if (keyGenParams instanceof SM4KeyGenParams) {
			SM4KeyGenParams sm4KeyGenParams = (SM4KeyGenParams) keyGenParams;
			SecretKey aesKey = genSecretKey(sm4KeyGenParams.getAlgorithm(), sm4KeyGenParams.getKeySize(), null, null);
			Map<String, Object> map = getSecretKeyMap(aesKey);
			sm4KeyGenParams.setKeyBase64((String) map.get("secretKeyBase64"));
			sm4KeyGenParams.setKeyHex((String) map.get("secretKeyHex"));
		}
	}

	/**
	 * 加密
	 *
	 * @param cipherParams 加密参数
	 * @throws InvalidKeyException                无效的密钥异常
	 * @throws NoSuchAlgorithmException           不支持该算法异常
	 * @throws NoSuchPaddingException             不支持填充方式异常
	 * @throws IllegalBlockSizeException          不合法的块大小异常
	 * @throws BadPaddingException                错误的填充方式异常
	 * @throws InvalidAlgorithmParameterException 无效的算法参数异常
	 * @throws InvalidKeySpecException            无效的密钥规范异常
	 * @throws IOException                        IO异常
	 */
	public static void encrypt(CipherParams cipherParams)
			throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException, IOException {
		if (cipherParams instanceof RSACipherParams) {
			RSACipherParams rsaCipherParams = (RSACipherParams) cipherParams;
			// 加载公钥用于加密
			Key key;
			if (!StringUtils.isEmpty(rsaCipherParams.getPubKeyPKCS1Pem())) {
				key = loadRSAPKCS1PublicKey(pemToDer(rsaCipherParams.getPubKeyPKCS1Pem()));
			} else if (!StringUtils.isEmpty(rsaCipherParams.getPubKeyX509Pem())) {
				key = loadX509Publickey(pemToDer(rsaCipherParams.getPubKeyX509Pem()), TYPE_ALGORITHM_RSA);
			} else {
				throw new InvalidKeyException("所输入参数公钥为空！");
			}
			byte[] plaintextArray;
			if (null != rsaCipherParams.getPlaintextArray()) {
				plaintextArray = rsaCipherParams.getPlaintextArray();
			} else if (!Strings.isNullOrEmpty(rsaCipherParams.getPlaintext())) {
				plaintextArray = rsaCipherParams.getPlaintext().getBytes(rsaCipherParams.getCharset());
			} else {
				throw new IOException("所输入参数明文为空！");
			}
			Map<String, String> map = encrypt(plaintextArray, key, rsaCipherParams.getAlgorithm(), rsaCipherParams.getMode(), rsaCipherParams.getPadding(), null);
			rsaCipherParams.setCiphertextArray(Hex.decode(map.get("ciphertextHex")));
			rsaCipherParams.setCiphertextBase64(map.get("ciphertextBase64"));
			rsaCipherParams.setCiphertextHex(map.get("ciphertextHex"));
		} else if (cipherParams instanceof SM2CipherParams) {
			SM2CipherParams sm2CipherParams = (SM2CipherParams) cipherParams;
			// 加载公钥用于加密
			Key key;
			if (!StringUtils.isEmpty(sm2CipherParams.getPubKeyHexFromQ())) {
				key = loadSM2HexPublickey(sm2CipherParams.getPubKeyHexFromQ());
			} else if (!StringUtils.isEmpty(sm2CipherParams.getPubKeyX509Pem())) {
				key = loadX509Publickey(pemToDer(sm2CipherParams.getPubKeyX509Pem()), sm2CipherParams.getAlgorithm());
			} else {
				throw new InvalidKeyException("所输入参数公钥为空！");
			}

			byte[] plaintextArray;
			if (null != sm2CipherParams.getPlaintextArray()) {
				plaintextArray = sm2CipherParams.getPlaintextArray();
			} else if (!Strings.isNullOrEmpty(sm2CipherParams.getPlaintext())) {
				plaintextArray = sm2CipherParams.getPlaintext().getBytes(sm2CipherParams.getCharset());
			} else {
				throw new IOException("所输入参数明文为空！");
			}
			Map<String, String> map = encrypt(plaintextArray, key, sm2CipherParams.getAlgorithm(), sm2CipherParams.getMode(), sm2CipherParams.getPadding(), null);
			sm2CipherParams.setCiphertextArray(Hex.decode(map.get("ciphertextHex")));
			sm2CipherParams.setCiphertextBase64(map.get("ciphertextBase64"));
			sm2CipherParams.setCiphertextHex(map.get("ciphertextHex"));
		} else if (cipherParams instanceof AESCipherParams) {
			AESCipherParams aesCipherParams = (AESCipherParams) cipherParams;
			// 加载公钥用于加密
			Key key;
			if (!StringUtils.isEmpty(aesCipherParams.getKeyBase64())) {
				key = loadSecretKey(Base64.getDecoder().decode(aesCipherParams.getKeyBase64()), aesCipherParams.getAlgorithm());
			} else if (!StringUtils.isEmpty(aesCipherParams.getKeyHex())) {
				key = loadSecretKey(Hex.decode(aesCipherParams.getKeyHex()), aesCipherParams.getAlgorithm());
			} else {
				throw new InvalidKeyException("所输入密钥为空！");
			}

			byte[] plaintextArray;
			if (null != aesCipherParams.getPlaintextArray()) {
				plaintextArray = aesCipherParams.getPlaintextArray();
			} else if (!Strings.isNullOrEmpty(aesCipherParams.getPlaintext())) {
				plaintextArray = aesCipherParams.getPlaintext().getBytes(aesCipherParams.getCharset());
			} else {
				throw new IOException("所输入参数明文为空！");
			}
			Map<String, String> map = encrypt(plaintextArray, key, aesCipherParams.getAlgorithm(), aesCipherParams.getMode(), aesCipherParams.getPadding(), aesCipherParams.getIV());
			aesCipherParams.setCiphertextArray(Hex.decode(map.get("ciphertextHex")));
			aesCipherParams.setCiphertextBase64(map.get("ciphertextBase64"));
			aesCipherParams.setCiphertextHex(map.get("ciphertextHex"));
			aesCipherParams.setIV(map.get("iv"));
		} else if (cipherParams instanceof DES3CipherParams) {
			DES3CipherParams des3CipherParams = (DES3CipherParams) cipherParams;
			// 加载公钥用于加密
			Key key;
			if (!StringUtils.isEmpty(des3CipherParams.getKeyBase64())) {
				key = loadSecretKey(Base64.getDecoder().decode(des3CipherParams.getKeyBase64()), des3CipherParams.getAlgorithm());
			} else if (!StringUtils.isEmpty(des3CipherParams.getKeyHex())) {
				key = loadSecretKey(Hex.decode(des3CipherParams.getKeyHex()), des3CipherParams.getAlgorithm());
			} else {
				throw new InvalidKeyException("所输入密钥为空！");
			}

			byte[] plaintextArray;
			if (null != des3CipherParams.getPlaintextArray()) {
				plaintextArray = des3CipherParams.getPlaintextArray();
			} else if (!Strings.isNullOrEmpty(des3CipherParams.getPlaintext())) {
				plaintextArray = des3CipherParams.getPlaintext().getBytes(des3CipherParams.getCharset());
			} else {
				throw new IOException("所输入参数明文为空！");
			}
			Map<String, String> map = encrypt(plaintextArray, key, des3CipherParams.getAlgorithm(), des3CipherParams.getMode(), des3CipherParams.getPadding(), des3CipherParams.getIV());
			des3CipherParams.setCiphertextArray(Hex.decode(map.get("ciphertextHex")));
			des3CipherParams.setCiphertextBase64(map.get("ciphertextBase64"));
			des3CipherParams.setCiphertextHex(map.get("ciphertextHex"));
			des3CipherParams.setIV(map.get("iv"));
		} else if (cipherParams instanceof SM4CipherParams) {
			SM4CipherParams sm4CipherParams = (SM4CipherParams) cipherParams;
			// 加载公钥用于加密
			Key key;
			if (!StringUtils.isEmpty(sm4CipherParams.getKeyBase64())) {
				key = loadSecretKey(Base64.getDecoder().decode(sm4CipherParams.getKeyBase64()), sm4CipherParams.getAlgorithm());
			} else if (!StringUtils.isEmpty(sm4CipherParams.getKeyHex())) {
				key = loadSecretKey(Hex.decode(sm4CipherParams.getKeyHex()), sm4CipherParams.getAlgorithm());
			} else {
				throw new InvalidKeyException("所输入密钥为空！");
			}

			byte[] plaintextArray;
			if (null != sm4CipherParams.getPlaintextArray()) {
				plaintextArray = sm4CipherParams.getPlaintextArray();
			} else if (!Strings.isNullOrEmpty(sm4CipherParams.getPlaintext())) {
				plaintextArray = sm4CipherParams.getPlaintext().getBytes(sm4CipherParams.getCharset());
			} else {
				throw new IOException("所输入参数明文为空！");
			}
			Map<String, String> map = encrypt(plaintextArray, key, sm4CipherParams.getAlgorithm(), sm4CipherParams.getMode(), sm4CipherParams.getPadding(), sm4CipherParams.getIV());
			sm4CipherParams.setCiphertextArray(Hex.decode(map.get("ciphertextHex")));
			sm4CipherParams.setCiphertextBase64(map.get("ciphertextBase64"));
			sm4CipherParams.setCiphertextHex(map.get("ciphertextHex"));
			sm4CipherParams.setIV(map.get("iv"));
		}

	}

	/**
	 * 解密
	 *
	 * @param cipherParams 解密参数
	 * @throws IOException                        IO异常
	 * @throws InvalidKeySpecException            无效的密钥规范异常
	 * @throws NoSuchAlgorithmException           不支持该算法异常
	 * @throws InvalidAlgorithmParameterException 无效的算法参数异常
	 * @throws NoSuchPaddingException             不支持填充方式异常
	 * @throws InvalidKeyException                无效的密钥异常
	 * @throws BadPaddingException                错误的填充方式异常
	 * @throws IllegalBlockSizeException          不合法的块大小异常
	 */
	public static void decrypt(CipherParams cipherParams)
			throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, InvalidKeyException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
		if (cipherParams instanceof RSACipherParams) {
			RSACipherParams rsaCipherParams = (RSACipherParams) cipherParams;
			// 加载私钥用于解密
			Key key;
			if (!StringUtils.isEmpty(rsaCipherParams.getPriKeyPKCS1Pem())) {
				if (StringUtils.isEmpty(rsaCipherParams.getPassword())) {
					key = loadRSAPKCS1PrivateKey(pemToDer(rsaCipherParams.getPriKeyPKCS1Pem()));
				} else {
					key = loadRSAPKCS1PrivateKey(pemToDer(decryptOpensslPrivateKey(rsaCipherParams.getPriKeyPKCS1Pem(), rsaCipherParams.getPassword())));
				}

			} else if (!StringUtils.isEmpty(rsaCipherParams.getPriKeyPKCS8Pem())) {
				if (StringUtils.isEmpty(rsaCipherParams.getPassword())) {
					key = loadPKCS8Privatekey(pemToDer(rsaCipherParams.getPriKeyPKCS8Pem()), TYPE_ALGORITHM_RSA);
				} else {
					key = loadPKCS8Privatekey(pemToDer(decryptPKCS8PrivateKey(rsaCipherParams.getPriKeyPKCS8Pem(), TYPE_ALGORITHM_RSA, rsaCipherParams.getPassword())), TYPE_ALGORITHM_RSA);
				}

			} else {
				throw new InvalidKeyException("所输入参数私钥为空！");
			}

			byte[] ciphertextArray;
			if (null != rsaCipherParams.getCiphertextArray()) {
				ciphertextArray = rsaCipherParams.getCiphertextArray();
			} else if (!StringUtils.isEmpty(rsaCipherParams.getCiphertextBase64())) {
				ciphertextArray = Base64.getDecoder().decode(rsaCipherParams.getCiphertextBase64());
			} else if (!StringUtils.isEmpty(rsaCipherParams.getCiphertextHex())) {
				ciphertextArray = Hex.decode(rsaCipherParams.getCiphertextHex());
			} else {
				throw new IOException("所输入密文为空！");
			}

			byte[] plaintextArray = decrypt(ciphertextArray, key, rsaCipherParams.getAlgorithm(), rsaCipherParams.getMode(), rsaCipherParams.getPadding(), null);
			rsaCipherParams.setPlaintextArray(plaintextArray);
			String plaintext = new String(plaintextArray, rsaCipherParams.getCharset());
			rsaCipherParams.setPlaintext(plaintext);
		} else if (cipherParams instanceof SM2CipherParams) {
			SM2CipherParams sm2CipherParams = (SM2CipherParams) cipherParams;
			// 加载私钥用于解密
			Key key;
			if (!StringUtils.isEmpty(sm2CipherParams.getPriKeyHexFromD())) {
				key = loadSM2HexPrivatekey(sm2CipherParams.getPriKeyHexFromD());
			} else if (!StringUtils.isEmpty(sm2CipherParams.getPriKeyGMTPem())) {
				if (StringUtils.isEmpty(sm2CipherParams.getPassword())) {
					key = loadSM2GMTPrivateKey(pemToDer(sm2CipherParams.getPriKeyGMTPem()));
				} else {
					key = loadSM2GMTPrivateKey(pemToDer(decryptOpensslPrivateKey(sm2CipherParams.getPriKeyGMTPem(), sm2CipherParams.getPassword())));
				}
			} else if (!StringUtils.isEmpty(sm2CipherParams.getPriKeyPKCS8Pem())) {
				if (StringUtils.isEmpty(sm2CipherParams.getPassword())) {
					key = loadPKCS8Privatekey(pemToDer(sm2CipherParams.getPriKeyPKCS8Pem()), TYPE_ALGORITHM_EC);
				} else {
					key = loadPKCS8Privatekey(pemToDer(decryptPKCS8PrivateKey(sm2CipherParams.getPriKeyPKCS8Pem(), TYPE_ALGORITHM_EC, sm2CipherParams.getPassword())), TYPE_ALGORITHM_EC);
				}

			} else {
				throw new InvalidKeyException("所输入参数私钥为空！");
			}

			byte[] ciphertextArray;
			if (null != sm2CipherParams.getCiphertextArray()) {
				ciphertextArray = sm2CipherParams.getCiphertextArray();
			} else if (!StringUtils.isEmpty(sm2CipherParams.getCiphertextBase64())) {
				ciphertextArray = Base64.getDecoder().decode(sm2CipherParams.getCiphertextBase64());
			} else if (!StringUtils.isEmpty(sm2CipherParams.getCiphertextHex())) {
				ciphertextArray = Hex.decode(sm2CipherParams.getCiphertextHex());
			} else {
				throw new IOException("所输入密文为空！");
			}

			byte[] plaintextArray = decrypt(ciphertextArray, key, sm2CipherParams.getAlgorithm(), sm2CipherParams.getMode(), sm2CipherParams.getPadding(), null);
			sm2CipherParams.setPlaintextArray(plaintextArray);
			String plaintext = new String(plaintextArray, sm2CipherParams.getCharset());
			sm2CipherParams.setPlaintext(plaintext);
		} else if (cipherParams instanceof AESCipherParams) {
			AESCipherParams aesCipherParams = (AESCipherParams) cipherParams;
			// 加载私钥用于解密
			Key key;
			if (!StringUtils.isEmpty(aesCipherParams.getKeyBase64())) {
				key = loadSecretKey(Base64.getDecoder().decode(aesCipherParams.getKeyBase64()), aesCipherParams.getAlgorithm());
			} else if (!StringUtils.isEmpty(aesCipherParams.getKeyHex())) {
				key = loadSecretKey(Hex.decode(aesCipherParams.getKeyHex()), aesCipherParams.getAlgorithm());
			} else {
				throw new InvalidKeyException("所输入密钥为空！");
			}

			byte[] ciphertextArray;
			if (null != aesCipherParams.getCiphertextArray()) {
				ciphertextArray = aesCipherParams.getCiphertextArray();
			} else if (!StringUtils.isEmpty(aesCipherParams.getCiphertextBase64())) {
				ciphertextArray = Base64.getDecoder().decode(aesCipherParams.getCiphertextBase64());
			} else if (!StringUtils.isEmpty(aesCipherParams.getCiphertextHex())) {
				ciphertextArray = Hex.decode(aesCipherParams.getCiphertextHex());
			} else {
				throw new IOException("所输入密文为空！");
			}

			byte[] plaintextArray = decrypt(ciphertextArray, key, aesCipherParams.getAlgorithm(), aesCipherParams.getMode(), aesCipherParams.getPadding(), aesCipherParams.getIV());
			aesCipherParams.setPlaintextArray(plaintextArray);
			String plaintext = new String(plaintextArray, aesCipherParams.getCharset());
			aesCipherParams.setPlaintext(plaintext);
		} else if (cipherParams instanceof DES3CipherParams) {
			DES3CipherParams des3CipherParams = (DES3CipherParams) cipherParams;
			// 加载私钥用于解密
			Key key;
			if (!StringUtils.isEmpty(des3CipherParams.getKeyBase64())) {
				key = loadSecretKey(Base64.getDecoder().decode(des3CipherParams.getKeyBase64()), des3CipherParams.getAlgorithm());
			} else if (!StringUtils.isEmpty(des3CipherParams.getKeyHex())) {
				key = loadSecretKey(Hex.decode(des3CipherParams.getKeyHex()), des3CipherParams.getAlgorithm());
			} else {
				throw new InvalidKeyException("所输入密钥为空！");
			}

			byte[] ciphertextArray;
			if (null != des3CipherParams.getCiphertextArray()) {
				ciphertextArray = des3CipherParams.getCiphertextArray();
			} else if (!StringUtils.isEmpty(des3CipherParams.getCiphertextBase64())) {
				ciphertextArray = Base64.getDecoder().decode(des3CipherParams.getCiphertextBase64());
			} else if (!StringUtils.isEmpty(des3CipherParams.getCiphertextHex())) {
				ciphertextArray = Hex.decode(des3CipherParams.getCiphertextHex());
			} else {
				throw new IOException("所输入密文为空！");
			}

			byte[] plaintextArray = decrypt(ciphertextArray, key, des3CipherParams.getAlgorithm(), des3CipherParams.getMode(), des3CipherParams.getPadding(), des3CipherParams.getIV());
			des3CipherParams.setPlaintextArray(plaintextArray);
			String plaintext = new String(plaintextArray, des3CipherParams.getCharset());
			des3CipherParams.setPlaintext(plaintext);
		} else if (cipherParams instanceof SM4CipherParams) {
			SM4CipherParams sm4CipherParams = (SM4CipherParams) cipherParams;
			// 加载私钥用于解密
			Key key;
			if (!StringUtils.isEmpty(sm4CipherParams.getKeyBase64())) {
				key = loadSecretKey(Base64.getDecoder().decode(sm4CipherParams.getKeyBase64()), sm4CipherParams.getAlgorithm());
			} else if (!StringUtils.isEmpty(sm4CipherParams.getKeyHex())) {
				key = loadSecretKey(Hex.decode(sm4CipherParams.getKeyHex()), sm4CipherParams.getAlgorithm());
			} else {
				throw new InvalidKeyException("所输入密钥为空！");
			}

			byte[] ciphertextArray;
			if (null != sm4CipherParams.getCiphertextArray()) {
				ciphertextArray = sm4CipherParams.getCiphertextArray();
			} else if (!StringUtils.isEmpty(sm4CipherParams.getCiphertextBase64())) {
				ciphertextArray = Base64.getDecoder().decode(sm4CipherParams.getCiphertextBase64());
			} else if (!StringUtils.isEmpty(sm4CipherParams.getCiphertextHex())) {
				ciphertextArray = Hex.decode(sm4CipherParams.getCiphertextHex());
			} else {
				throw new IOException("所输入密文为空！");
			}

			byte[] plaintextArray = decrypt(ciphertextArray, key, sm4CipherParams.getAlgorithm(), sm4CipherParams.getMode(), sm4CipherParams.getPadding(), sm4CipherParams.getIV());
			sm4CipherParams.setPlaintextArray(plaintextArray);
			String plaintext = new String(plaintextArray, sm4CipherParams.getCharset());
			sm4CipherParams.setPlaintext(plaintext);
		}

	}

	/**
	 * 签名
	 *
	 * @param signatureParams 签名参数
	 * @throws IOException                        IO异常
	 * @throws InvalidKeySpecException            无效的密钥规范异常
	 * @throws NoSuchAlgorithmException           不支持该算法异常
	 * @throws InvalidAlgorithmParameterException 无效的算法参数异常
	 * @throws NoSuchPaddingException             不支持填充方式异常
	 * @throws InvalidKeyException                无效的密钥异常
	 * @throws SignatureException                 签名异常
	 */
	public static void sign(SignatureParams signatureParams) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, InvalidKeyException, NoSuchPaddingException, InvalidAlgorithmParameterException, SignatureException {
		if (signatureParams instanceof RSASignatureParams) {
			RSASignatureParams rsaSignatureParams = (RSASignatureParams) signatureParams;
			// 加载私钥用于签名
			PrivateKey privateKey;
			if (!StringUtils.isEmpty(rsaSignatureParams.getPriKeyPKCS1Pem())) {
				if (StringUtils.isEmpty(rsaSignatureParams.getPassword())) {
					privateKey = loadRSAPKCS1PrivateKey(pemToDer(rsaSignatureParams.getPriKeyPKCS1Pem()));
				} else {
					privateKey = loadRSAPKCS1PrivateKey(pemToDer(decryptOpensslPrivateKey(rsaSignatureParams.getPriKeyPKCS1Pem(), rsaSignatureParams.getPassword())));
				}

			} else if (!StringUtils.isEmpty(rsaSignatureParams.getPriKeyPKCS8Pem())) {
				if (StringUtils.isEmpty(rsaSignatureParams.getPassword())) {
					privateKey = loadPKCS8Privatekey(pemToDer(rsaSignatureParams.getPriKeyPKCS8Pem()), TYPE_ALGORITHM_RSA);
				} else {
					privateKey = loadPKCS8Privatekey(pemToDer(decryptPKCS8PrivateKey(rsaSignatureParams.getPriKeyPKCS8Pem(), TYPE_ALGORITHM_RSA, rsaSignatureParams.getPassword())), TYPE_ALGORITHM_RSA);
				}

			} else {
				throw new InvalidKeyException("所输入参数私钥为空！");
			}

			byte[] plaintextArray;
			if (null != rsaSignatureParams.getPlaintextArray()) {
				plaintextArray = rsaSignatureParams.getPlaintextArray();
			} else if (!Strings.isNullOrEmpty(rsaSignatureParams.getPlaintext())) {
				plaintextArray = rsaSignatureParams.getPlaintext().getBytes(rsaSignatureParams.getCharset());
			} else {
				throw new IOException("所输入参数明文为空！");
			}

			byte[] signatureArray = sign(plaintextArray, privateKey, rsaSignatureParams.getAlgorithm());
			signatureParams.setSignatureArray(signatureArray);
			signatureParams.setSignatureBase64(Base64.getEncoder().encodeToString(signatureArray));
			signatureParams.setSignatureHex(Hex.toHexString(signatureArray));
		} else if (signatureParams instanceof DSASignatureParams) {
			DSASignatureParams dsaSignatureParams = (DSASignatureParams) signatureParams;
			// 加载私钥用于签名
			PrivateKey privateKey;
			if (!StringUtils.isEmpty(dsaSignatureParams.getPriKeyPKCS1Pem())) {
				if (StringUtils.isEmpty(dsaSignatureParams.getPassword())) {
					privateKey = loadDSAPKCS1PrivateKey(pemToDer(dsaSignatureParams.getPriKeyPKCS1Pem()));
				} else {
					privateKey = loadDSAPKCS1PrivateKey(pemToDer(decryptOpensslPrivateKey(dsaSignatureParams.getPriKeyPKCS1Pem(), dsaSignatureParams.getPassword())));
				}

			} else if (!StringUtils.isEmpty(dsaSignatureParams.getPriKeyPKCS8Pem())) {
				if (StringUtils.isEmpty(dsaSignatureParams.getPassword())) {
					privateKey = loadPKCS8Privatekey(pemToDer(dsaSignatureParams.getPriKeyPKCS8Pem()), TYPE_ALGORITHM_DSA);
				} else {
					privateKey = loadPKCS8Privatekey(pemToDer(decryptPKCS8PrivateKey(dsaSignatureParams.getPriKeyPKCS8Pem(), TYPE_ALGORITHM_DSA, dsaSignatureParams.getPassword())), TYPE_ALGORITHM_DSA);
				}

			} else {
				throw new InvalidKeyException("所输入参数私钥为空！");
			}

			byte[] plaintextArray;
			if (null != dsaSignatureParams.getPlaintextArray()) {
				plaintextArray = dsaSignatureParams.getPlaintextArray();
			} else if (!Strings.isNullOrEmpty(dsaSignatureParams.getPlaintext())) {
				plaintextArray = dsaSignatureParams.getPlaintext().getBytes(dsaSignatureParams.getCharset());
			} else {
				throw new IOException("所输入参数明文为空！");
			}

			byte[] signatureArray = sign(plaintextArray, privateKey, dsaSignatureParams.getAlgorithm());
			signatureParams.setSignatureArray(signatureArray);
			signatureParams.setSignatureBase64(Base64.getEncoder().encodeToString(signatureArray));
			signatureParams.setSignatureHex(Hex.toHexString(signatureArray));
		} else if (signatureParams instanceof SM2SignatureParams) {
			SM2SignatureParams sm2SignatureParams = (SM2SignatureParams) signatureParams;
			// 加载私钥用于签名
			PrivateKey privateKey;
			if (!StringUtils.isEmpty(sm2SignatureParams.getPriKeyHexFromD())) {
				privateKey = loadSM2HexPrivatekey(sm2SignatureParams.getPriKeyHexFromD());
			} else if (!StringUtils.isEmpty(sm2SignatureParams.getPriKeyGMTPem())) {
				if (StringUtils.isEmpty(sm2SignatureParams.getPassword())) {
					privateKey = loadSM2GMTPrivateKey(pemToDer(sm2SignatureParams.getPriKeyGMTPem()));
				} else {
					privateKey = loadSM2GMTPrivateKey(pemToDer(decryptOpensslPrivateKey(sm2SignatureParams.getPriKeyGMTPem(), sm2SignatureParams.getPassword())));
				}
			} else if (!StringUtils.isEmpty(sm2SignatureParams.getPriKeyPKCS8Pem())) {
				if (StringUtils.isEmpty(sm2SignatureParams.getPassword())) {
					privateKey = loadPKCS8Privatekey(pemToDer(sm2SignatureParams.getPriKeyPKCS8Pem()), TYPE_ALGORITHM_EC);
				} else {
					privateKey = loadPKCS8Privatekey(pemToDer(decryptPKCS8PrivateKey(sm2SignatureParams.getPriKeyPKCS8Pem(), TYPE_ALGORITHM_EC, sm2SignatureParams.getPassword())), TYPE_ALGORITHM_EC);
				}

			} else {
				throw new InvalidKeyException("所输入参数私钥为空！");
			}

			byte[] plaintextArray;
			if (null != sm2SignatureParams.getPlaintextArray()) {
				plaintextArray = sm2SignatureParams.getPlaintextArray();
			} else if (!Strings.isNullOrEmpty(sm2SignatureParams.getPlaintext())) {
				plaintextArray = sm2SignatureParams.getPlaintext().getBytes(sm2SignatureParams.getCharset());
			} else {
				throw new IOException("所输入参数明文为空！");
			}

			byte[] signatureArray = sign(plaintextArray, privateKey, sm2SignatureParams.getAlgorithm());
			signatureParams.setSignatureArray(signatureArray);
			signatureParams.setSignatureBase64(Base64.getEncoder().encodeToString(signatureArray));
			signatureParams.setSignatureHex(Hex.toHexString(signatureArray));
		}
	}

	/**
	 * 验签
	 *
	 * @param signatureParams 验签参数
	 * @throws NoSuchAlgorithmException           不支持该算法异常
	 * @throws InvalidKeySpecException            无效的密钥规范异常
	 * @throws IOException                        IO异常
	 * @throws InvalidKeyException                无效的密钥异常
	 * @throws SignatureException                 签名异常
	 * @throws InvalidAlgorithmParameterException 无效的算法参数异常
	 */
	public static void verify(SignatureParams signatureParams) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, InvalidKeyException, SignatureException, InvalidAlgorithmParameterException {
		if (signatureParams instanceof RSASignatureParams) {
			RSASignatureParams rsaSignatureParams = (RSASignatureParams) signatureParams;
			// 加载公钥用于验签
			PublicKey publicKey;
			if (!StringUtils.isEmpty(rsaSignatureParams.getPubKeyPKCS1Pem())) {
				publicKey = loadRSAPKCS1PublicKey(pemToDer(rsaSignatureParams.getPubKeyPKCS1Pem()));
			} else if (!StringUtils.isEmpty(rsaSignatureParams.getPubKeyX509Pem())) {
				publicKey = loadX509Publickey(pemToDer(rsaSignatureParams.getPubKeyX509Pem()), TYPE_ALGORITHM_RSA);
			} else {
				throw new InvalidKeyException("所输入参数公钥为空！");
			}

			byte[] signatureArray;
			if (null != signatureParams.getSignatureArray()) {
				signatureArray = signatureParams.getSignatureArray();
			} else if (!StringUtils.isEmpty(signatureParams.getSignatureBase64())) {
				signatureArray = Base64.getDecoder().decode(signatureParams.getSignatureBase64());
			} else if (!StringUtils.isEmpty(signatureParams.getSignatureHex())) {
				signatureArray = Hex.decode(signatureParams.getSignatureHex());
			} else {
				throw new IOException("所输入参数签名为空！");
			}

			byte[] plaintextArray;
			if (null != rsaSignatureParams.getPlaintextArray()) {
				plaintextArray = rsaSignatureParams.getPlaintextArray();
			} else if (!Strings.isNullOrEmpty(rsaSignatureParams.getPlaintext())) {
				plaintextArray = rsaSignatureParams.getPlaintext().getBytes(rsaSignatureParams.getCharset());
			} else {
				throw new IOException("所输入参数明文为空！");
			}

			boolean result = verify(plaintextArray, signatureArray, publicKey, rsaSignatureParams.getAlgorithm());
			signatureParams.setVerifyResult(result);
		} else if (signatureParams instanceof DSASignatureParams) {
			DSASignatureParams dsaSignatureParams = (DSASignatureParams) signatureParams;
			// 加载公钥用于验签
			PublicKey publicKey;
			if (!StringUtils.isEmpty(dsaSignatureParams.getPubKeyX509Pem())) {
				publicKey = loadX509Publickey(pemToDer(dsaSignatureParams.getPubKeyX509Pem()), TYPE_ALGORITHM_DSA);
			} else {
				throw new InvalidKeyException("所输入参数公钥为空！");
			}

			byte[] signatureArray;
			if (null != signatureParams.getSignatureArray()) {
				signatureArray = signatureParams.getSignatureArray();
			} else if (!StringUtils.isEmpty(signatureParams.getSignatureBase64())) {
				signatureArray = Base64.getDecoder().decode(signatureParams.getSignatureBase64());
			} else if (!StringUtils.isEmpty(signatureParams.getSignatureHex())) {
				signatureArray = Hex.decode(signatureParams.getSignatureHex());
			} else {
				throw new IOException("所输入参数签名为空！");
			}

			byte[] plaintextArray;
			if (null != dsaSignatureParams.getPlaintextArray()) {
				plaintextArray = dsaSignatureParams.getPlaintextArray();
			} else if (!Strings.isNullOrEmpty(dsaSignatureParams.getPlaintext())) {
				plaintextArray = dsaSignatureParams.getPlaintext().getBytes(dsaSignatureParams.getCharset());
			} else {
				throw new IOException("所输入参数明文为空！");
			}
			boolean result = verify(plaintextArray, signatureArray, publicKey, dsaSignatureParams.getAlgorithm());
			signatureParams.setVerifyResult(result);
		} else if (signatureParams instanceof SM2SignatureParams) {
			SM2SignatureParams sm2SignatureParams = (SM2SignatureParams) signatureParams;
			// 加载公钥用于验签
			PublicKey publicKey;
			if (!StringUtils.isEmpty(sm2SignatureParams.getPubKeyHexFromQ())) {
				publicKey = loadSM2HexPublickey(sm2SignatureParams.getPubKeyHexFromQ());
			} else if (!StringUtils.isEmpty(sm2SignatureParams.getPubKeyX509Pem())) {
				publicKey = loadX509Publickey(pemToDer(sm2SignatureParams.getPubKeyX509Pem()), TYPE_ALGORITHM_EC);
			} else {
				throw new InvalidKeyException("所输入参数公钥为空！");
			}

			byte[] signatureArray;
			if (null != signatureParams.getSignatureArray()) {
				signatureArray = signatureParams.getSignatureArray();
			} else if (!StringUtils.isEmpty(signatureParams.getSignatureBase64())) {
				signatureArray = Base64.getDecoder().decode(signatureParams.getSignatureBase64());
			} else if (!StringUtils.isEmpty(signatureParams.getSignatureHex())) {
				signatureArray = Hex.decode(signatureParams.getSignatureHex());
			} else {
				throw new IOException("所输入参数签名为空！");
			}

			byte[] plaintextArray;
			if (null != sm2SignatureParams.getPlaintextArray()) {
				plaintextArray = sm2SignatureParams.getPlaintextArray();
			} else if (!Strings.isNullOrEmpty(sm2SignatureParams.getPlaintext())) {
				plaintextArray = sm2SignatureParams.getPlaintext().getBytes(sm2SignatureParams.getCharset());
			} else {
				throw new IOException("所输入参数明文为空！");
			}

			boolean result = verify(plaintextArray, signatureArray, publicKey, sm2SignatureParams.getAlgorithm());
			signatureParams.setVerifyResult(result);
		}
	}

	/**
	 * 计算散列值
	 *
	 * @param messageDigestParams 计算散列值参数
	 * @throws NoSuchAlgorithmException     不支持该算法异常
	 * @throws UnsupportedEncodingException 不支持的编码方式异常
	 */
	public static void hash(MessageDigestParams messageDigestParams) throws NoSuchAlgorithmException, UnsupportedEncodingException {
		if (messageDigestParams instanceof MessageDigestParamsImpl) {
			byte[] plaintextArray;
			if (null != messageDigestParams.getPlaintextArray()) {
				plaintextArray = messageDigestParams.getPlaintextArray();
			} else if (!Strings.isNullOrEmpty(messageDigestParams.getPlaintext())) {
				plaintextArray = messageDigestParams.getPlaintext().getBytes(messageDigestParams.getCharset());
			} else {
				plaintextArray = new byte[0];
			}

			byte[] hashArray = hash(plaintextArray, messageDigestParams.getAlgorithm());
			messageDigestParams.setHashValueArray(hashArray);
			messageDigestParams.setHashValueBase64(Base64.getEncoder().encodeToString(hashArray));
			messageDigestParams.setHashValueHex(Hex.toHexString(hashArray));
		}
	}

	public static void main(String[] args) throws Exception {
		// 对于多种数据源的问题，现在的方法还是遍历，找到一种数据源便结束寻找。如输入明文数组和明文字符串，则只有数组有效。而密文和签名中的值则是先数组，然后b64、hex
//		testRSA();
//		testDSA();
//		testSM2();
//		testAES();
//		test3DES();
//		testSM4();
		testHash();
//		RSAKeyGenParams rsaKeyGenParams = new RSAKeyGenParams();
//		rsaKeyGenParams.setKeySize(1024);
//		rsaKeyGenParams.setPassword("123457");
//		KeyUtil.genKey(rsaKeyGenParams);
//		System.out.println("");
//		isEncryptedPemKey(rsaKeyGenParams.getPriKeyPKCS1Pem());
//		isEncryptedPemKey(rsaKeyGenParams.getPriKeyPKCS8Pem());
//		isEncryptedPemKey(rsaKeyGenParams.getPubKeyPKCS1Pem());
//		isEncryptedPemKey(rsaKeyGenParams.getPubKeyX509Pem());
//		rsaKeyGenParams = new RSAKeyGenParams();
//		rsaKeyGenParams.setKeySize(1024);
//		KeyUtil.genKey(rsaKeyGenParams);
//		isEncryptedPemKey(rsaKeyGenParams.getPriKeyPKCS1Pem());
//		isEncryptedPemKey(rsaKeyGenParams.getPriKeyPKCS8Pem());
//		isEncryptedPemKey(rsaKeyGenParams.getPubKeyPKCS1Pem());
//		isEncryptedPemKey(rsaKeyGenParams.getPubKeyX509Pem());
//		System.out.println();
//
//		DSAKeyGenParams dsaKeyGenParams = new DSAKeyGenParams();
//		dsaKeyGenParams.setKeySize(1024);
//		dsaKeyGenParams.setPassword("123457");
//		KeyUtil.genKey(dsaKeyGenParams);
//		isEncryptedPemKey(dsaKeyGenParams.getPriKeyPKCS1Pem());
//		isEncryptedPemKey(dsaKeyGenParams.getPriKeyPKCS8Pem());
//		isEncryptedPemKey(dsaKeyGenParams.getPubKeyX509Pem());
//		dsaKeyGenParams = new DSAKeyGenParams();
//		dsaKeyGenParams.setKeySize(1024);
//		KeyUtil.genKey(dsaKeyGenParams);
//		isEncryptedPemKey(dsaKeyGenParams.getPriKeyPKCS1Pem());
//		isEncryptedPemKey(dsaKeyGenParams.getPriKeyPKCS8Pem());
//		isEncryptedPemKey(dsaKeyGenParams.getPubKeyX509Pem());
//		System.out.println();
//
//		SM2KeyGenParams sm2KeyGenParams = new SM2KeyGenParams();
//		sm2KeyGenParams.setPassword("123457");
//		KeyUtil.genKey(sm2KeyGenParams);
//		isEncryptedPemKey(sm2KeyGenParams.getPriKeyGMTPem());
//		isEncryptedPemKey(sm2KeyGenParams.getPriKeyPKCS8Pem());
//		isEncryptedPemKey(sm2KeyGenParams.getPubKeyX509Pem());
//		sm2KeyGenParams = new SM2KeyGenParams();
//		KeyUtil.genKey(sm2KeyGenParams);
//		isEncryptedPemKey(sm2KeyGenParams.getPriKeyGMTPem());
//		isEncryptedPemKey(sm2KeyGenParams.getPriKeyPKCS8Pem());
//		isEncryptedPemKey(sm2KeyGenParams.getPubKeyX509Pem());
//		System.out.println();
	}

	static String plaintext = "浪潮inspur123!@#$%^&*()_+";

	private static void testRSA() throws Exception {
		// 密钥生成
		RSAKeyGenParams rsaKeyGenParams = new RSAKeyGenParams();
		rsaKeyGenParams.setKeySize(1024);
		rsaKeyGenParams.setPassword("123457");
		KeyUtil.genKey(rsaKeyGenParams);
		System.out.println(JSON.toJSONString(rsaKeyGenParams));
		// 加密
		RSACipherParams rsaCipherParams = new RSACipherParams();
		rsaCipherParams.setPlaintext(plaintext);
//        rsaCipherParams.setPlaintextArray(plaintextArray);
		rsaCipherParams.setCharset("utf-8");// 默认utf-8，可更换
		rsaCipherParams.setPubKeyX509Pem(rsaKeyGenParams.getPubKeyX509Pem());
		KeyUtil.encrypt(rsaCipherParams);
		System.out.println(JSON.toJSONString(rsaCipherParams));
		// 解密
		RSACipherParams rsaCipherParams2 = new RSACipherParams();
		rsaCipherParams2.setCiphertextBase64(rsaCipherParams.getCiphertextBase64());
//        rsaCipherParams2.setCiphertextArray(plaintextArray);
		rsaCipherParams2.setCharset("utf-8");// 默认utf-8，可更换
		rsaCipherParams2.setPriKeyPKCS8Pem(rsaKeyGenParams.getPriKeyPKCS8Pem());
		rsaCipherParams2.setPassword("123457");
		KeyUtil.decrypt(rsaCipherParams2);
		System.out.println(JSON.toJSONString(rsaCipherParams2));
		// 签名
		RSASignatureParams rsaSignatureParams = new RSASignatureParams();
		rsaSignatureParams.setPlaintext(plaintext);
//        rsaSignatureParams.setPlaintextArray(plaintextArray);
		rsaSignatureParams.setCharset("utf-8");// 默认utf-8，可更换
		rsaSignatureParams.setPriKeyPKCS1Pem(rsaKeyGenParams.getPriKeyPKCS1Pem());
		rsaSignatureParams.setAlgorithm("md5withRSA");
		rsaSignatureParams.setPassword("123457");
		KeyUtil.sign(rsaSignatureParams);
		System.out.println(JSON.toJSONString(rsaSignatureParams));
		// 验签
		RSASignatureParams rsaSignatureParams1 = new RSASignatureParams();
		rsaSignatureParams1.setPlaintext(plaintext);
		rsaSignatureParams1.setCharset("utf-8");// 默认utf-8，可更换
        rsaSignatureParams1.setSignatureBase64(rsaSignatureParams.getSignatureBase64());
//		rsaSignatureParams1.setSignatureArray(plaintextArray);
		rsaSignatureParams1.setPubKeyX509Pem(rsaKeyGenParams.getPubKeyX509Pem());
		rsaSignatureParams1.setAlgorithm("md5withRSA");
		KeyUtil.verify(rsaSignatureParams1);
		System.out.println(JSON.toJSONString(rsaSignatureParams1));
	}

	private static void testDSA() throws Exception {
//		byte[] plaintextArray = new byte[127000];
//		byte a = 20;
//		Arrays.fill(plaintextArray, a);
		// 密钥生成
		DSAKeyGenParams dsaKeyGenParams = new DSAKeyGenParams();
		dsaKeyGenParams.setKeySize(1024);
		dsaKeyGenParams.setPassword("123457");
		KeyUtil.genKey(dsaKeyGenParams);
		System.out.println(JSON.toJSONString(dsaKeyGenParams));
		// 签名
		DSASignatureParams dsaSignatureParams = new DSASignatureParams();
		dsaSignatureParams.setPlaintext(plaintext);
		dsaSignatureParams.setCharset("utf-8");// 默认utf-8，可更换
//		dsaSignatureParams.setPriKeyPKCS8Pem(dsaKeyGenParams.getPriKeyPKCS8Pem());
		dsaSignatureParams.setPriKeyPKCS1Pem(dsaKeyGenParams.getPriKeyPKCS1Pem());
		dsaSignatureParams.setAlgorithm("SHA1withDSA");
		dsaSignatureParams.setPassword("123457");
		KeyUtil.sign(dsaSignatureParams);
		System.out.println(JSON.toJSONString(dsaSignatureParams));
		// 验签
		DSASignatureParams dsaSignatureParams1 = new DSASignatureParams();
		dsaSignatureParams1.setPlaintext(plaintext);
		dsaSignatureParams1.setCharset("utf-8");// 默认utf-8，可更换
		dsaSignatureParams1.setSignatureArray(dsaSignatureParams.getSignatureArray());
		dsaSignatureParams1.setPubKeyX509Pem(dsaKeyGenParams.getPubKeyX509Pem());
		dsaSignatureParams1.setAlgorithm("SHA1withDSA");
		KeyUtil.verify(dsaSignatureParams1);
		System.out.println(JSON.toJSONString(dsaSignatureParams1));
	}

	private static void testSM2() throws Exception {
//		byte[] plaintextArray = new byte[10018];
//		byte a = 20;
//		Arrays.fill(plaintextArray, a);
		// 密钥生成
		SM2KeyGenParams sm2KeyGenParams = new SM2KeyGenParams();
		sm2KeyGenParams.setPassword("123457");
		KeyUtil.genKey(sm2KeyGenParams);
		System.out.println(JSON.toJSONString(sm2KeyGenParams));
		// 加密
		SM2CipherParams sm2CipherParams = new SM2CipherParams();
        sm2CipherParams.setPlaintext(plaintext);
//		sm2CipherParams.setPlaintextArray(plaintextArray);
		sm2CipherParams.setCharset("utf-8");// 默认utf-8，可更换
		sm2CipherParams.setPubKeyX509Pem(sm2KeyGenParams.getPubKeyX509Pem());
		KeyUtil.encrypt(sm2CipherParams);
		System.out.println(JSON.toJSONString(sm2CipherParams));
		// 解密
		SM2CipherParams sm2CipherParams2 = new SM2CipherParams();
		sm2CipherParams2.setCiphertextBase64(sm2CipherParams.getCiphertextBase64());
		sm2CipherParams2.setCharset("utf-8");// 默认utf-8，可更换
		sm2CipherParams2.setPriKeyPKCS8Pem(sm2KeyGenParams.getPriKeyPKCS8Pem());
		sm2CipherParams2.setPassword("123457");
		KeyUtil.decrypt(sm2CipherParams2);
		System.out.println(JSON.toJSONString(sm2CipherParams2));
		// 签名
		SM2SignatureParams sm2SignatureParams = new SM2SignatureParams();
		sm2SignatureParams.setPlaintext(plaintext);
		sm2SignatureParams.setCharset("utf-8");// 默认utf-8，可更换
		sm2SignatureParams.setPriKeyPKCS8Pem(sm2KeyGenParams.getPriKeyPKCS8Pem());
//        sm2SignatureParams.setPriKeyGMTPem(sm2KeyGenParams.getPriKeyGMTPem());
		sm2SignatureParams.setAlgorithm("SM3WITHSM2");
		sm2SignatureParams.setPassword("123457");
		KeyUtil.sign(sm2SignatureParams);
		System.out.println(JSON.toJSONString(sm2SignatureParams));
		// 验签
		SM2SignatureParams sm2SignatureParams1 = new SM2SignatureParams();
		sm2SignatureParams1.setPlaintext(plaintext);
		sm2SignatureParams1.setCharset("utf-8");// 默认utf-8，可更换
		sm2SignatureParams1.setSignatureBase64(sm2SignatureParams.getSignatureBase64());
		sm2SignatureParams1.setPubKeyX509Pem(sm2KeyGenParams.getPubKeyX509Pem());
		sm2SignatureParams1.setAlgorithm("SM3WITHSM2");
		KeyUtil.verify(sm2SignatureParams1);
		System.out.println(JSON.toJSONString(sm2SignatureParams1));
	}

	private static void testAES() throws Exception {
		// 密钥生成
		AESKeyGenParams aesKeyGenParams = new AESKeyGenParams();
		aesKeyGenParams.setKeySize(256);
		KeyUtil.genKey(aesKeyGenParams);
		System.out.println(JSON.toJSONString(aesKeyGenParams));
		// 加密
		AESCipherParams aesCipherParams = new AESCipherParams();
		aesCipherParams.setPlaintext(plaintext);
		aesCipherParams.setCharset("utf-8");// 默认utf-8，可更换
		aesCipherParams.setKeyBase64(aesKeyGenParams.getKeyBase64());
		aesCipherParams.setMode("CBC");
		aesCipherParams.setPadding("PKCS5Padding");
		aesCipherParams.setIV("67f1f009d2f8d7a5d7c14c4d2fd17087");
		KeyUtil.encrypt(aesCipherParams);
		System.out.println(JSON.toJSONString(aesCipherParams));
		// 解密
		AESCipherParams aesCipherParams2 = new AESCipherParams();
		aesCipherParams2.setCiphertextBase64(aesCipherParams.getCiphertextBase64());
		aesCipherParams2.setCharset("utf-8");// 默认utf-8，可更换
		aesCipherParams2.setKeyBase64(aesKeyGenParams.getKeyBase64());
		aesCipherParams2.setMode("CBC");
		aesCipherParams2.setPadding("PKCS5Padding");
		aesCipherParams2.setIV(aesCipherParams.getIV());// 解密时，若是CBC模式，则必须指定IV
		KeyUtil.decrypt(aesCipherParams2);
		System.out.println(JSON.toJSONString(aesCipherParams2));
	}

	private static void test3DES() throws Exception {
		// 密钥生成
		DES3KeyGenParams des3KeyGenParams = new DES3KeyGenParams();
		des3KeyGenParams.setKeySize(192);
		KeyUtil.genKey(des3KeyGenParams);
		System.out.println(JSON.toJSONString(des3KeyGenParams));
		// 加密
		DES3CipherParams des3CipherParams = new DES3CipherParams();
		des3CipherParams.setPlaintext(plaintext);
		des3CipherParams.setCharset("utf-8");// 默认utf-8，可更换
		des3CipherParams.setKeyBase64(des3KeyGenParams.getKeyBase64());
		des3CipherParams.setMode("CBC");
		des3CipherParams.setPadding("PKCS5Padding");
//		des3CipherParams.setIV(des3CipherParams.getIV());//解密时，若是CBC模式，则必须指定IV
		KeyUtil.encrypt(des3CipherParams);
		System.out.println(JSON.toJSONString(des3CipherParams));
		// 解密
		DES3CipherParams des3CipherParams1 = new DES3CipherParams();
		des3CipherParams1.setCiphertextBase64(des3CipherParams.getCiphertextBase64());
		des3CipherParams1.setCharset("utf-8");// 默认utf-8，可更换
		des3CipherParams1.setKeyBase64(des3CipherParams.getKeyBase64());
		des3CipherParams1.setMode("CBC");
		des3CipherParams1.setPadding("PKCS5Padding");
		des3CipherParams1.setIV(des3CipherParams.getIV());// 解密时，若是CBC模式，则必须指定IV
		KeyUtil.decrypt(des3CipherParams1);
		System.out.println(JSON.toJSONString(des3CipherParams1));
	}

	private static void testSM4() throws Exception {
		// 密钥生成
		SM4KeyGenParams sm4KeyGenParams = new SM4KeyGenParams();
//		sm4KeyGenParams.setKeySize(128);//考虑到SM4密钥长度固定，不再允许设置密钥长度
		KeyUtil.genKey(sm4KeyGenParams);
		System.out.println(JSON.toJSONString(sm4KeyGenParams));
		// 加密
		SM4CipherParams sm4CipherParams = new SM4CipherParams();
		sm4CipherParams.setPlaintext(plaintext);
		sm4CipherParams.setCharset("utf-8");// 默认utf-8，可更换
		sm4CipherParams.setKeyBase64(sm4KeyGenParams.getKeyBase64());
		sm4CipherParams.setMode("CBC");
		sm4CipherParams.setPadding("PKCS5Padding");
//		sm4CipherParams.setIV(des3CipherParams.getIV());//解密时，若是CBC模式，则必须指定IV
		KeyUtil.encrypt(sm4CipherParams);
		System.out.println(JSON.toJSONString(sm4CipherParams));
		// 解密
		SM4CipherParams sm4CipherParams1 = new SM4CipherParams();
		sm4CipherParams1.setCiphertextBase64(sm4CipherParams.getCiphertextBase64());
		sm4CipherParams1.setCharset("utf-8");// 默认utf-8，可更换
		sm4CipherParams1.setKeyBase64(sm4CipherParams.getKeyBase64());
		sm4CipherParams1.setMode("CBC");
		sm4CipherParams1.setPadding("PKCS5Padding");
		sm4CipherParams1.setIV(sm4CipherParams.getIV());// 解密时，若是CBC模式，则必须指定IV
		KeyUtil.decrypt(sm4CipherParams1);
		System.out.println(JSON.toJSONString(sm4CipherParams1));
	}

	private static void testHash(){
		MessageDigestParamsImpl params = new MessageDigestParamsImpl();
		params.setPlaintext(plaintext);
		params.setCharset("utf-8");// 默认utf-8，可更换
		params.setAlgorithm("aa");
		try {
			KeyUtil.hash(params);
		} catch (Exception e) {
			String error = e.getMessage();
			System.out.println(e.getMessage());
			System.out.println(e.toString());
		}
		System.out.println(JSON.toJSONString(params));
	}

}
